]> granicus.if.org Git - clang/commitdiff
Rework how we support C++ implicit member accesses. If we can resolve an
authorJohn McCall <rjmccall@apple.com>
Tue, 1 Dec 2009 22:10:20 +0000 (22:10 +0000)
committerJohn McCall <rjmccall@apple.com>
Tue, 1 Dec 2009 22:10:20 +0000 (22:10 +0000)
implicit member access to a specific declaration, go ahead and create
it as a DeclRefExpr or a MemberExpr (with implicit CXXThisExpr base) as
appropriate.  Otherwise, create an UnresolvedMemberExpr or
DependentScopeMemberExpr with a null base expression.

By representing implicit accesses directly in the AST, we get the ability
to correctly delay the decision about whether it's actually an instance
member access or not until resolution is complete.  This permits us
to correctly avoid diagnosing the 'problem' of 'MyType::foo()'
where the relationship to the type isn't really known until instantiation.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90266 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ExprCXX.h
lib/AST/ExprCXX.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/TreeTransform.h
test/SemaTemplate/instantiate-method.cpp
test/SemaTemplate/qualified-id.cpp

index 23844ce5d9678e92fb73a3cd3dc3475cf743c3db..66f4b5d2b5cd5062045a60da6b89dd8550d5fef8 100644 (file)
@@ -1410,18 +1410,26 @@ public:
 /// \brief Represents a C++ member access expression where the actual
 /// member referenced could not be resolved because the base
 /// expression or the member name was dependent.
+///
+/// Like UnresolvedMemberExprs, these can be either implicit or
+/// explicit accesses.  It is only possible to get one of these with
+/// an implicit access if a qualifier is provided.
 class CXXDependentScopeMemberExpr : public Expr {
   /// \brief The expression for the base pointer or class reference,
-  /// e.g., the \c x in x.f.
+  /// e.g., the \c x in x.f.  Can be null in implicit accesses.
   Stmt *Base;
 
+  /// \brief The type of the base expression.  Never null, even for
+  /// implicit accesses.
+  QualType BaseType;
+
   /// \brief Whether this member expression used the '->' operator or
   /// the '.' operator.
   bool IsArrow : 1;
 
   /// \brief Whether this member expression has explicitly-specified template
   /// arguments.
-  bool HasExplicitTemplateArgumentList : 1;
+  bool HasExplicitTemplateArgs : 1;
 
   /// \brief The location of the '->' or '.' operator.
   SourceLocation OperatorLoc;
@@ -1452,9 +1460,7 @@ class CXXDependentScopeMemberExpr : public Expr {
   /// \brief Retrieve the explicit template argument list that followed the
   /// member template name, if any.
   ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() {
-    if (!HasExplicitTemplateArgumentList)
-      return 0;
-
+    assert(HasExplicitTemplateArgs);
     return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
   }
 
@@ -1466,7 +1472,7 @@ class CXXDependentScopeMemberExpr : public Expr {
   }
 
   CXXDependentScopeMemberExpr(ASTContext &C,
-                          Expr *Base, bool IsArrow,
+                          Expr *Base, QualType BaseType, bool IsArrow,
                           SourceLocation OperatorLoc,
                           NestedNameSpecifier *Qualifier,
                           SourceRange QualifierRange,
@@ -1477,7 +1483,8 @@ class CXXDependentScopeMemberExpr : public Expr {
 
 public:
   CXXDependentScopeMemberExpr(ASTContext &C,
-                          Expr *Base, bool IsArrow,
+                          Expr *Base, QualType BaseType,
+                          bool IsArrow,
                           SourceLocation OperatorLoc,
                           NestedNameSpecifier *Qualifier,
                           SourceRange QualifierRange,
@@ -1485,15 +1492,15 @@ public:
                           DeclarationName Member,
                           SourceLocation MemberLoc)
   : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true),
-    Base(Base), IsArrow(IsArrow), HasExplicitTemplateArgumentList(false),
-    OperatorLoc(OperatorLoc),
+    Base(Base), BaseType(BaseType), IsArrow(IsArrow),
+    HasExplicitTemplateArgs(false), OperatorLoc(OperatorLoc),
     Qualifier(Qualifier), QualifierRange(QualifierRange),
     FirstQualifierFoundInScope(FirstQualifierFoundInScope),
     Member(Member), MemberLoc(MemberLoc) { }
 
   static CXXDependentScopeMemberExpr *
   Create(ASTContext &C,
-         Expr *Base, bool IsArrow,
+         Expr *Base, QualType BaseType, bool IsArrow,
          SourceLocation OperatorLoc,
          NestedNameSpecifier *Qualifier,
          SourceRange QualifierRange,
@@ -1502,11 +1509,21 @@ public:
          SourceLocation MemberLoc,
          const TemplateArgumentListInfo *TemplateArgs);
 
+  /// \brief True if this is an implicit access, i.e. one in which the
+  /// member being accessed was not written in the source.  The source
+  /// location of the operator is invalid in this case.
+  bool isImplicitAccess() const { return Base == 0; }
+
   /// \brief Retrieve the base object of this member expressions,
   /// e.g., the \c x in \c x.m.
-  Expr *getBase() { return cast<Expr>(Base); }
+  Expr *getBase() const {
+    assert(!isImplicitAccess());
+    return cast<Expr>(Base);
+  }
   void setBase(Expr *E) { Base = E; }
 
+  QualType getBaseType() const { return BaseType; }
+
   /// \brief Determine whether this member expression used the '->'
   /// operator; otherwise, it used the '.' operator.
   bool isArrow() const { return IsArrow; }
@@ -1551,60 +1568,59 @@ public:
 
   /// \brief Determines whether this member expression actually had a C++
   /// template argument list explicitly specified, e.g., x.f<int>.
-  bool hasExplicitTemplateArgumentList() const {
-    return HasExplicitTemplateArgumentList;
+  bool hasExplicitTemplateArgs() const {
+    return HasExplicitTemplateArgs;
   }
 
   /// \brief Copies the template arguments (if present) into the given
   /// structure.
   void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
-    if (hasExplicitTemplateArgumentList())
-      getExplicitTemplateArgumentList()->copyInto(List);
+    assert(HasExplicitTemplateArgs);
+    getExplicitTemplateArgumentList()->copyInto(List);
   }
 
   /// \brief Retrieve the location of the left angle bracket following the
   /// member name ('<'), if any.
   SourceLocation getLAngleLoc() const {
-    if (!HasExplicitTemplateArgumentList)
-      return SourceLocation();
-
+    assert(HasExplicitTemplateArgs);
     return getExplicitTemplateArgumentList()->LAngleLoc;
   }
 
   /// \brief Retrieve the template arguments provided as part of this
   /// template-id.
   const TemplateArgumentLoc *getTemplateArgs() const {
-    if (!HasExplicitTemplateArgumentList)
-      return 0;
-
+    assert(HasExplicitTemplateArgs);
     return getExplicitTemplateArgumentList()->getTemplateArgs();
   }
 
   /// \brief Retrieve the number of template arguments provided as part of this
   /// template-id.
   unsigned getNumTemplateArgs() const {
-    if (!HasExplicitTemplateArgumentList)
-      return 0;
-
+    assert(HasExplicitTemplateArgs);
     return getExplicitTemplateArgumentList()->NumTemplateArgs;
   }
 
   /// \brief Retrieve the location of the right angle bracket following the
   /// template arguments ('>').
   SourceLocation getRAngleLoc() const {
-    if (!HasExplicitTemplateArgumentList)
-      return SourceLocation();
-
+    assert(HasExplicitTemplateArgs);
     return getExplicitTemplateArgumentList()->RAngleLoc;
   }
 
   virtual SourceRange getSourceRange() const {
-    if (HasExplicitTemplateArgumentList)
-      return SourceRange(Base->getSourceRange().getBegin(),
-                         getRAngleLoc());
+    SourceRange Range;
+    if (!isImplicitAccess())
+      Range.setBegin(Base->getSourceRange().getBegin());
+    else if (getQualifier())
+      Range.setBegin(getQualifierRange().getBegin());
+    else
+      Range.setBegin(MemberLoc);
 
-    return SourceRange(Base->getSourceRange().getBegin(),
-                       MemberLoc);
+    if (hasExplicitTemplateArgs())
+      Range.setEnd(getRAngleLoc());
+    else
+      Range.setEnd(MemberLoc);
+    return Range;
   }
 
   static bool classof(const Stmt *T) {
@@ -1618,17 +1634,31 @@ public:
 };
 
 /// \brief Represents a C++ member access expression for which lookup
-/// produced a set of overloaded functions.  These are replaced with
-/// MemberExprs in the final AST.
+/// produced a set of overloaded functions.
+///
+/// The member access may be explicit or implicit:
+///    struct A {
+///      int a, b;
+///      int explicitAccess() { return this->a + this->A::b; }
+///      int implicitAccess() { return a + A::b; }
+///    };
+///
+/// In the final AST, an explicit access always becomes a MemberExpr.
+/// An implicit access may become either a MemberExpr or a
+/// DeclRefExpr, depending on whether the member is static.
 class UnresolvedMemberExpr : public Expr {
   /// The results.  These are undesugared, which is to say, they may
   /// include UsingShadowDecls.
   UnresolvedSet Results;
 
   /// \brief The expression for the base pointer or class reference,
-  /// e.g., the \c x in x.f.
+  /// e.g., the \c x in x.f.  This can be null if this is an 'unbased'
+  /// member expression
   Stmt *Base;
 
+  /// \brief The type of the base expression;  never null.
+  QualType BaseType;
+
   /// \brief Whether this member expression used the '->' operator or
   /// the '.' operator.
   bool IsArrow : 1;
@@ -1672,7 +1702,7 @@ class UnresolvedMemberExpr : public Expr {
 
   UnresolvedMemberExpr(QualType T, bool Dependent,
                        bool HasUnresolvedUsing,
-                       Expr *Base, bool IsArrow,
+                       Expr *Base, QualType BaseType, bool IsArrow,
                        SourceLocation OperatorLoc,
                        NestedNameSpecifier *Qualifier,
                        SourceRange QualifierRange,
@@ -1683,7 +1713,7 @@ class UnresolvedMemberExpr : public Expr {
 public:
   static UnresolvedMemberExpr *
   Create(ASTContext &C, bool Dependent, bool HasUnresolvedUsing,
-         Expr *Base, bool IsArrow,
+         Expr *Base, QualType BaseType, bool IsArrow,
          SourceLocation OperatorLoc,
          NestedNameSpecifier *Qualifier,
          SourceRange QualifierRange,
@@ -1704,11 +1734,21 @@ public:
 
   unsigned getNumDecls() const { return Results.size(); }
 
+  /// \brief True if this is an implicit access, i.e. one in which the
+  /// member being accessed was not written in the source.  The source
+  /// location of the operator is invalid in this case.
+  bool isImplicitAccess() const { return Base == 0; }
+
   /// \brief Retrieve the base object of this member expressions,
   /// e.g., the \c x in \c x.m.
-  Expr *getBase() { return cast<Expr>(Base); }
+  Expr *getBase() {
+    assert(!isImplicitAccess());
+    return cast<Expr>(Base);
+  }
   void setBase(Expr *E) { Base = E; }
 
+  QualType getBaseType() const { return BaseType; }
+
   /// \brief Determine whether this member expression used the '->'
   /// operator; otherwise, it used the '.' operator.
   bool isArrow() const { return IsArrow; }
@@ -1772,7 +1812,14 @@ public:
   }
 
   virtual SourceRange getSourceRange() const {
-    SourceRange Range = Base->getSourceRange();
+    SourceRange Range;
+    if (!isImplicitAccess())
+      Range.setBegin(Base->getSourceRange().getBegin());
+    else if (getQualifier())
+      Range.setBegin(getQualifierRange().getBegin());
+    else
+      Range.setBegin(MemberLoc);
+
     if (hasExplicitTemplateArgs())
       Range.setEnd(getRAngleLoc());
     else
index d1a0390a0a68b9fa1794573c25c2f687daca56e7..7a6fbdca8bceffecd1d3721f0b22de2c3716f149 100644 (file)
@@ -518,7 +518,8 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() {
 }
 
 CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
-                                                 Expr *Base, bool IsArrow,
+                                                 Expr *Base, QualType BaseType,
+                                                 bool IsArrow,
                                                  SourceLocation OperatorLoc,
                                                  NestedNameSpecifier *Qualifier,
                                                  SourceRange QualifierRange,
@@ -527,8 +528,8 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
                                                  SourceLocation MemberLoc,
                                    const TemplateArgumentListInfo *TemplateArgs)
   : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true),
-    Base(Base), IsArrow(IsArrow),
-    HasExplicitTemplateArgumentList(TemplateArgs),
+    Base(Base), BaseType(BaseType), IsArrow(IsArrow),
+    HasExplicitTemplateArgs(TemplateArgs != 0),
     OperatorLoc(OperatorLoc),
     Qualifier(Qualifier), QualifierRange(QualifierRange),
     FirstQualifierFoundInScope(FirstQualifierFoundInScope),
@@ -539,7 +540,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
 
 CXXDependentScopeMemberExpr *
 CXXDependentScopeMemberExpr::Create(ASTContext &C,
-                                Expr *Base, bool IsArrow,
+                                Expr *Base, QualType BaseType, bool IsArrow,
                                 SourceLocation OperatorLoc,
                                 NestedNameSpecifier *Qualifier,
                                 SourceRange QualifierRange,
@@ -548,22 +549,22 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C,
                                 SourceLocation MemberLoc,
                                 const TemplateArgumentListInfo *TemplateArgs) {
   if (!TemplateArgs)
-    return new (C) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc,
-                                           Qualifier, QualifierRange,
-                                           FirstQualifierFoundInScope,
-                                           Member, MemberLoc);
+    return new (C) CXXDependentScopeMemberExpr(C, Base, BaseType,
+                                               IsArrow, OperatorLoc,
+                                               Qualifier, QualifierRange,
+                                               FirstQualifierFoundInScope,
+                                               Member, MemberLoc);
 
   std::size_t size = sizeof(CXXDependentScopeMemberExpr);
   if (TemplateArgs)
     size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
 
   void *Mem = C.Allocate(size, llvm::alignof<CXXDependentScopeMemberExpr>());
-  return new (Mem) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc,
-                                           Qualifier, QualifierRange,
-                                           FirstQualifierFoundInScope,
-                                           Member,
-                                           MemberLoc,
-                                           TemplateArgs);
+  return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType,
+                                               IsArrow, OperatorLoc,
+                                               Qualifier, QualifierRange,
+                                               FirstQualifierFoundInScope,
+                                               Member, MemberLoc, TemplateArgs);
 }
 
 Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() {
@@ -571,12 +572,15 @@ Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() {
 }
 
 Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() {
+  if (isImplicitAccess())
+    return child_iterator(&Base);
   return child_iterator(&Base + 1);
 }
 
 UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
                                            bool HasUnresolvedUsing,
-                                           Expr *Base, bool IsArrow,
+                                           Expr *Base, QualType BaseType,
+                                           bool IsArrow,
                                            SourceLocation OperatorLoc,
                                            NestedNameSpecifier *Qualifier,
                                            SourceRange QualifierRange,
@@ -584,7 +588,8 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
                                            SourceLocation MemberLoc,
                                    const TemplateArgumentListInfo *TemplateArgs)
   : Expr(UnresolvedMemberExprClass, T, Dependent, Dependent),
-    Base(Base), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing),
+    Base(Base), BaseType(BaseType), IsArrow(IsArrow),
+    HasUnresolvedUsing(HasUnresolvedUsing),
     HasExplicitTemplateArgs(TemplateArgs != 0),
     OperatorLoc(OperatorLoc),
     Qualifier(Qualifier), QualifierRange(QualifierRange),
@@ -596,7 +601,7 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
 UnresolvedMemberExpr *
 UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent,
                              bool HasUnresolvedUsing,
-                             Expr *Base, bool IsArrow,
+                             Expr *Base, QualType BaseType, bool IsArrow,
                              SourceLocation OperatorLoc,
                              NestedNameSpecifier *Qualifier,
                              SourceRange QualifierRange,
@@ -610,8 +615,8 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent,
   void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>());
   return new (Mem) UnresolvedMemberExpr(
                              Dependent ? C.DependentTy : C.OverloadTy,
-                             Dependent, HasUnresolvedUsing, Base, IsArrow,
-                             OperatorLoc, Qualifier, QualifierRange,
+                             Dependent, HasUnresolvedUsing, Base, BaseType,
+                             IsArrow, OperatorLoc, Qualifier, QualifierRange,
                              Member, MemberLoc, TemplateArgs);
 }
 
@@ -620,5 +625,7 @@ Stmt::child_iterator UnresolvedMemberExpr::child_begin() {
 }
 
 Stmt::child_iterator UnresolvedMemberExpr::child_end() {
+  if (isImplicitAccess())
+    return child_iterator(&Base);
   return child_iterator(&Base + 1);
 }
index 205ea0d182d408f146e62f7c8c189099a0fc33d5..a7e42af04d81bc40510bfd8a24ea22d65e5ccce9 100644 (file)
@@ -1145,17 +1145,19 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr(
 
 void StmtPrinter::VisitCXXDependentScopeMemberExpr(
                                          CXXDependentScopeMemberExpr *Node) {
-  PrintExpr(Node->getBase());
-  OS << (Node->isArrow() ? "->" : ".");
+  if (!Node->isImplicitAccess()) {
+    PrintExpr(Node->getBase());
+    OS << (Node->isArrow() ? "->" : ".");
+  }
   if (NestedNameSpecifier *Qualifier = Node->getQualifier())
     Qualifier->print(OS, Policy);
-  else if (Node->hasExplicitTemplateArgumentList())
+  else if (Node->hasExplicitTemplateArgs())
     // FIXME: Track use of "template" keyword explicitly?
     OS << "template ";
 
   OS << Node->getMember().getAsString();
 
-  if (Node->hasExplicitTemplateArgumentList()) {
+  if (Node->hasExplicitTemplateArgs()) {
     OS << TemplateSpecializationType::PrintTemplateArgumentList(
                                                     Node->getTemplateArgs(),
                                                     Node->getNumTemplateArgs(),
@@ -1164,8 +1166,10 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr(
 }
 
 void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
-  PrintExpr(Node->getBase());
-  OS << (Node->isArrow() ? "->" : ".");
+  if (!Node->isImplicitAccess()) {
+    PrintExpr(Node->getBase());
+    OS << (Node->isArrow() ? "->" : ".");
+  }
   if (NestedNameSpecifier *Qualifier = Node->getQualifier())
     Qualifier->print(OS, Policy);
 
index d832a4649e752afe8e662c7028482c3ba0f8724f..1b6b022901e90d66ec411bfbb312b65cbbc9c2d9 100644 (file)
@@ -554,18 +554,24 @@ StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) {
 
 void
 StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) {
-  VisitExpr(S);
-  ID.AddBoolean(S->isArrow());
+  ID.AddBoolean(S->isImplicitAccess());
+  if (!S->isImplicitAccess()) {
+    VisitExpr(S);
+    ID.AddBoolean(S->isArrow());
+  }
   VisitNestedNameSpecifier(S->getQualifier());
   VisitName(S->getMember());
-  ID.AddBoolean(S->hasExplicitTemplateArgumentList());
-  if (S->hasExplicitTemplateArgumentList())
+  ID.AddBoolean(S->hasExplicitTemplateArgs());
+  if (S->hasExplicitTemplateArgs())
     VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
 }
 
 void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) {
-  VisitExpr(S);
-  ID.AddBoolean(S->isArrow());
+  ID.AddBoolean(S->isImplicitAccess());
+  if (!S->isImplicitAccess()) {
+    VisitExpr(S);
+    ID.AddBoolean(S->isArrow());
+  }
   VisitNestedNameSpecifier(S->getQualifier());
   VisitName(S->getMemberName());
   ID.AddBoolean(S->hasExplicitTemplateArgs());
index f961406e3e540bfb1563daf4f630849289357341..4b437995f15d00ca572ff1fe7a1009865a834502 100644 (file)
@@ -1023,7 +1023,7 @@ public:
                                                       SourceLocation RLoc,
                                                       ExprArg Base,ExprArg Idx);
 
-  ExprResult
+  OwningExprResult
   BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
                             SourceLocation LParenLoc, Expr **Args,
                             unsigned NumArgs, SourceLocation *CommaLocs,
@@ -1451,9 +1451,10 @@ public:
                                            FieldDecl *Field,
                                            Expr *BaseObjectExpr = 0,
                                       SourceLocation OpLoc = SourceLocation());
-  OwningExprResult BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS,
-                                                    LookupResult &R,
-                                const TemplateArgumentListInfo *TemplateArgs);
+  OwningExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS,
+                                           LookupResult &R,
+                                const TemplateArgumentListInfo *TemplateArgs,
+                                           bool IsDefiniteInstance);
   bool UseArgumentDependentLookup(const CXXScopeSpec &SS,
                                   const LookupResult &R,
                                   bool HasTrailingLParen);
@@ -1525,6 +1526,7 @@ public:
                                                    SourceLocation RLoc);
 
   OwningExprResult BuildMemberReferenceExpr(ExprArg Base,
+                                            QualType BaseType,
                                             SourceLocation OpLoc,
                                             bool IsArrow,
                                             const CXXScopeSpec &SS,
@@ -1534,6 +1536,7 @@ public:
                                 const TemplateArgumentListInfo *TemplateArgs);
 
   OwningExprResult BuildMemberReferenceExpr(ExprArg Base,
+                                            QualType BaseType,
                                             SourceLocation OpLoc, bool IsArrow,
                                             const CXXScopeSpec &SS,
                                             LookupResult &R,
@@ -1551,6 +1554,7 @@ public:
                                      const LookupResult &R);
 
   OwningExprResult ActOnDependentMemberExpr(ExprArg Base,
+                                            QualType BaseType,
                                             bool IsArrow,
                                             SourceLocation OpLoc,
                                             const CXXScopeSpec &SS,
@@ -1592,6 +1596,11 @@ public:
                                          MultiExprArg Args,
                                          SourceLocation *CommaLocs,
                                          SourceLocation RParenLoc);
+  OwningExprResult BuildResolvedCallExpr(Expr *Fn,
+                                         NamedDecl *NDecl,
+                                         SourceLocation LParenLoc,
+                                         Expr **Args, unsigned NumArgs,
+                                         SourceLocation RParenLoc);
 
   virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
                                          TypeTy *Ty, SourceLocation RParenLoc,
index bf14d0d3032be07d6b96542a310ca48eafae136a..8e14fcdd6b29d783c53f72df826bc9e64ca5481e 100644 (file)
@@ -703,18 +703,173 @@ static bool IsDependentIdExpression(Sema &SemaRef, const CXXScopeSpec &SS) {
   // We can't look into record types unless they're fully-formed.
   if (!IsFullyFormedScope(SemaRef, cast<CXXRecordDecl>(DC))) return true;
 
-  // We can always look into fully-formed record types, but if we're
-  // in a dependent but not fully-formed context, we can't decide
-  // whether the qualifier names a base class.  We shouldn't be trying
-  // to decide that yet anyway, but we are, so we need to delay that
-  // decision.
-  CXXRecordDecl *CurRecord;
-  if (CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(SemaRef.CurContext))
-    CurRecord = cast<CXXRecordDecl>(CurMethod->getParent());
-  else
-    CurRecord = dyn_cast<CXXRecordDecl>(SemaRef.CurContext);
+  return false;
+}
+
+/// Determines if the given class is provably not derived from all of
+/// the prospective base classes.
+static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
+                                     CXXRecordDecl *Record,
+                            const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) {
+  Record = Record->getCanonicalDecl();
+  if (Bases.count(Record))
+    return false;
+
+  for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
+         E = Record->bases_end(); I != E; ++I) {
+    CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
+    CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>();
+    if (!BaseRT) return false;
+
+    CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
+    if (!BaseRecord->isDefinition())
+      return false;
+
+    if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases))
+      return false;
+  }
+
+  return true;
+}
+                                  
+static bool IsInstanceMember(NamedDecl *D) {
+  assert(isa<CXXRecordDecl>(D->getDeclContext()) &&
+         "checking whether non-member is instance member");
+
+  if (isa<FieldDecl>(D)) return true;
+  
+  if (isa<CXXMethodDecl>(D))
+    return !cast<CXXMethodDecl>(D)->isStatic();
+
+  if (isa<FunctionTemplateDecl>(D)) {
+    D = cast<FunctionTemplateDecl>(D)->getTemplatedDecl();
+    return !cast<CXXMethodDecl>(D)->isStatic();
+  }
+
+  return false;
+}
+
+enum IMAKind {
+  /// The reference is definitely not an instance member access.
+  IMA_Static,
+
+  /// The reference may be an implicit instance member access.
+  IMA_Mixed,
+
+  /// The reference may be to an instance member, but it is invalid if
+  /// so, because the context is not an instance method.
+  IMA_Mixed_StaticContext,
+
+  /// The reference may be to an instance member, but it is invalid if
+  /// so, because the context is from an unrelated class.
+  IMA_Mixed_Unrelated,
+
+  /// The reference is definitely an implicit instance member access.
+  IMA_Instance,
+
+  /// The reference may be to an unresolved using declaration.
+  IMA_Unresolved,
+
+  /// The reference may be to an unresolved using declaration and the
+  /// context is not an instance method.
+  IMA_Unresolved_StaticContext,
+
+  /// The reference is to a member of an anonymous structure in a
+  /// non-class context.
+  IMA_AnonymousMember,
+
+  /// All possible referrents are instance members and the current
+  /// context is not an instance method.
+  IMA_Error_StaticContext,
+
+  /// All possible referrents are instance members of an unrelated
+  /// class.
+  IMA_Error_Unrelated
+};
 
-  return CurRecord && !IsFullyFormedScope(SemaRef, CurRecord);
+/// The given lookup names class member(s) and is not being used for
+/// an address-of-member expression.  Classify the type of access
+/// according to whether it's possible that this reference names an
+/// instance member.  This is best-effort; it is okay to
+/// conservatively answer "yes", in which case some errors will simply
+/// not be caught until template-instantiation.
+static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
+                                            const LookupResult &R) {
+  assert(!R.empty() && isa<CXXRecordDecl>((*R.begin())->getDeclContext()));
+
+  bool isStaticContext =
+    (!isa<CXXMethodDecl>(SemaRef.CurContext) ||
+     cast<CXXMethodDecl>(SemaRef.CurContext)->isStatic());
+
+  if (R.isUnresolvableResult())
+    return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
+
+  // Collect all the declaring classes of instance members we find.
+  bool hasNonInstance = false;
+  llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
+  for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+    NamedDecl *D = (*I)->getUnderlyingDecl();
+    if (IsInstanceMember(D)) {
+      CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
+
+      // If this is a member of an anonymous record, move out to the
+      // innermost non-anonymous struct or union.  If there isn't one,
+      // that's a special case.
+      while (R->isAnonymousStructOrUnion()) {
+        R = dyn_cast<CXXRecordDecl>(R->getParent());
+        if (!R) return IMA_AnonymousMember;
+      }
+      Classes.insert(R->getCanonicalDecl());
+    }
+    else
+      hasNonInstance = true;
+  }
+
+  // If we didn't find any instance members, it can't be an implicit
+  // member reference.
+  if (Classes.empty())
+    return IMA_Static;
+
+  // If the current context is not an instance method, it can't be
+  // an implicit member reference.
+  if (isStaticContext)
+    return (hasNonInstance ? IMA_Mixed_StaticContext : IMA_Error_StaticContext);
+
+  // If we can prove that the current context is unrelated to all the
+  // declaring classes, it can't be an implicit member reference (in
+  // which case it's an error if any of those members are selected).
+  if (IsProvablyNotDerivedFrom(SemaRef,
+                        cast<CXXMethodDecl>(SemaRef.CurContext)->getParent(),
+                               Classes))
+    return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
+
+  return (hasNonInstance ? IMA_Mixed : IMA_Instance);
+}
+
+/// Diagnose a reference to a field with no object available.
+static void DiagnoseInstanceReference(Sema &SemaRef,
+                                      const CXXScopeSpec &SS,
+                                      const LookupResult &R) {
+  SourceLocation Loc = R.getNameLoc();
+  SourceRange Range(Loc);
+  if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
+
+  if (R.getAsSingle<FieldDecl>()) {
+    if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) {
+      if (MD->isStatic()) {
+        // "invalid use of member 'x' in static member function"
+        SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
+          << Range << R.getLookupName();
+        return;
+      }
+    }
+
+    SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
+      << R.getLookupName() << Range;
+    return;
+  }
+
+  SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
 }
 
 Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
@@ -847,23 +1002,41 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
     }
   }
 
-  // &SomeClass::foo is an abstract member reference, regardless of
-  // the nature of foo, but &SomeClass::foo(...) is not.  If this is
-  // *not* an abstract member reference, and any of the results is a
-  // class member (which necessarily means they're all class members),
-  // then we make an implicit member reference instead.
-  //
-  // This check considers all the same information as the "needs ADL"
-  // check, but there's no simple logical relationship other than the
-  // fact that they can never be simultaneously true.  We could
-  // calculate them both in one pass if that proves important for
-  // performance.
-  if (!ADL) {
+  // Check whether this might be a C++ implicit instance member access.
+  // C++ [expr.prim.general]p6:
+  //   Within the definition of a non-static member function, an
+  //   identifier that names a non-static member is transformed to a
+  //   class member access expression.
+  // But note that &SomeClass::foo is grammatically distinct, even
+  // though we don't parse it that way.
+  if (!R.empty() && (*R.begin())->getDeclContext()->isRecord()) {
     bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty());
 
-    if (!isAbstractMemberPointer && !R.empty() &&
-        isa<CXXRecordDecl>((*R.begin())->getDeclContext())) {
-      return BuildImplicitMemberReferenceExpr(SS, R, TemplateArgs);
+    if (!isAbstractMemberPointer) {
+      switch (ClassifyImplicitMemberAccess(*this, R)) {
+      case IMA_Instance:
+        return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
+
+      case IMA_AnonymousMember:
+        assert(R.isSingleResult());
+        return BuildAnonymousStructUnionMemberReference(R.getNameLoc(),
+                                                 R.getAsSingle<FieldDecl>());
+
+      case IMA_Mixed:
+      case IMA_Mixed_Unrelated:
+      case IMA_Unresolved:
+        return BuildImplicitMemberExpr(SS, R, TemplateArgs, false);
+
+      case IMA_Static:
+      case IMA_Mixed_StaticContext:
+      case IMA_Unresolved_StaticContext:
+        break;
+
+      case IMA_Error_StaticContext:
+      case IMA_Error_Unrelated:
+        DiagnoseInstanceReference(*this, SS, R);
+        return ExprError();
+      }
     }
   }
 
@@ -1041,35 +1214,15 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
                             Member, Loc, TemplateArgs, Ty);
 }
 
-/// Return true if all the decls in the given result are instance
-/// methods.
-static bool IsOnlyInstanceMethods(const LookupResult &R) {
-  for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
-    NamedDecl *D = (*I)->getUnderlyingDecl();
-
-    CXXMethodDecl *Method;
-    if (isa<FunctionTemplateDecl>(D))
-      Method = cast<CXXMethodDecl>(cast<FunctionTemplateDecl>(D)
-                                   ->getTemplatedDecl());
-    else if (isa<CXXMethodDecl>(D))
-      Method = cast<CXXMethodDecl>(D);
-    else
-      return false;
-
-    if (Method->isStatic())
-      return false;
-  }
-
-  return true;
-}
-
-/// Builds an implicit member access expression from the given
-/// unqualified lookup set, which is known to contain only class
-/// members.
+/// Builds an implicit member access expression.  The current context
+/// is known to be an instance method, and the given unqualified lookup
+/// set is known to contain only instance members, at least one of which
+/// is from an appropriate type.
 Sema::OwningExprResult
-Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS,
-                                       LookupResult &R,
-                              const TemplateArgumentListInfo *TemplateArgs) {
+Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
+                              LookupResult &R,
+                              const TemplateArgumentListInfo *TemplateArgs,
+                              bool IsKnownInstance) {
   assert(!R.empty() && !R.isAmbiguous());
 
   SourceLocation Loc = R.getNameLoc();
@@ -1082,44 +1235,18 @@ Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS,
     if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion())
       return BuildAnonymousStructUnionMemberReference(Loc, FD);
 
-  QualType ThisType;
-  if (isImplicitMemberReference(R, ThisType)) {
-    Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
-    return BuildMemberReferenceExpr(ExprArg(*this, This),
-                                    /*OpLoc*/ SourceLocation(),
-                                    /*IsArrow*/ true,
-                                    SS, R, TemplateArgs);
+  // If this is known to be an instance access, go ahead and build a
+  // 'this' expression now.
+  QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context);
+  Expr *This = 0; // null signifies implicit access
+  if (IsKnownInstance) {
+    This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
   }
 
-  // Diagnose now if none of the available methods are static.
-  if (IsOnlyInstanceMethods(R))
-    return ExprError(Diag(Loc, diag::err_member_call_without_object));
-
-  if (R.getAsSingle<FieldDecl>()) {
-    if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
-      if (MD->isStatic()) {
-        // "invalid use of member 'x' in static member function"
-        Diag(Loc, diag::err_invalid_member_use_in_static_method)
-          << R.getLookupName();
-        return ExprError();
-      }
-    }
-
-    // Any other ways we could have found the field in a well-formed
-    // program would have been turned into implicit member expressions
-    // above.
-    Diag(Loc, diag::err_invalid_non_static_member_use)
-      << R.getLookupName();
-    return ExprError();
-  }
-
-  // We're not in an implicit member-reference context, but the lookup
-  // results might not require an instance.  Try to build a non-member
-  // decl reference.
-  if (TemplateArgs)
-    return BuildTemplateIdExpr(SS, R, /* ADL */ false, *TemplateArgs);
-
-  return BuildDeclarationNameExpr(SS, R, /*ADL*/ false);
+  return BuildMemberReferenceExpr(ExprArg(*this, This), ThisType,
+                                  /*OpLoc*/ SourceLocation(),
+                                  /*IsArrow*/ true,
+                                  SS, R, TemplateArgs);
 }
 
 bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
@@ -1205,8 +1332,6 @@ Sema::OwningExprResult
 Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
                                LookupResult &R,
                                bool NeedsADL) {
-  assert(R.getResultKind() != LookupResult::FoundUnresolvedValue);
-
   // If this isn't an overloaded result and we don't need ADL, just
   // build an ordinary singleton decl ref.
   if (!NeedsADL && !R.isOverloadedResult())
@@ -1968,7 +2093,8 @@ static Decl *FindGetterNameDecl(const ObjCObjectPointerType *QIdTy,
 }
 
 Sema::OwningExprResult
-Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc,
+Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType,
+                               bool IsArrow, SourceLocation OpLoc,
                                const CXXScopeSpec &SS,
                                NamedDecl *FirstQualifierInScope,
                                DeclarationName Name, SourceLocation NameLoc,
@@ -1985,20 +2111,21 @@ Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc,
   // accessing the 'f' property if T is an Obj-C interface. The extra check
   // allows this, while still reporting an error if T is a struct pointer.
   if (!IsArrow) {
-    const PointerType *PT = BaseExpr->getType()->getAs<PointerType>();
+    const PointerType *PT = BaseType->getAs<PointerType>();
     if (PT && (!getLangOptions().ObjC1 ||
                PT->getPointeeType()->isRecordType())) {
+      assert(BaseExpr && "cannot happen with implicit member accesses");
       Diag(NameLoc, diag::err_typecheck_member_reference_struct_union)
-        << BaseExpr->getType() << BaseExpr->getSourceRange();
+        << BaseType << BaseExpr->getSourceRange();
       return ExprError();
     }
   }
 
-  assert(BaseExpr->getType()->isDependentType());
+  assert(BaseType->isDependentType());
 
   // 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.
-  return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr,
+  return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType,
                                                    IsArrow, OpLoc,
                  static_cast<NestedNameSpecifier*>(SS.getScopeRep()),
                                                    SS.getRange(),
@@ -2041,34 +2168,71 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr,
                                          NestedNameSpecifier *Qualifier,
                                          SourceRange QualifierRange,
                                          const LookupResult &R) {
-  QualType BaseTypeCanon
-    = Context.getCanonicalType(BaseType).getUnqualifiedType();
-
-  bool FoundValid = false;
+  const RecordType *BaseRT = BaseType->getAs<RecordType>();
+  if (!BaseRT) {
+    // We can't check this yet because the base type is still
+    // dependent.
+    assert(BaseType->isDependentType());
+    return false;
+  }
+  CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
 
   for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
-    TypeDecl* TyD = cast<TypeDecl>((*I)->getUnderlyingDecl()->getDeclContext());
-    CanQualType MemberTypeCanon
-      = Context.getCanonicalType(Context.getTypeDeclType(TyD));
+    // If this is an implicit member reference and we find a
+    // non-instance member, it's not an error.
+    if (!BaseExpr && !IsInstanceMember((*I)->getUnderlyingDecl()))
+      return false;
 
-    if (BaseTypeCanon == MemberTypeCanon ||
-        IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) {
-      FoundValid = true;
-      break;
-    }
+    // Note that we use the DC of the decl, not the underlying decl.
+    CXXRecordDecl *RecordD = cast<CXXRecordDecl>((*I)->getDeclContext());
+    while (RecordD->isAnonymousStructOrUnion())
+      RecordD = cast<CXXRecordDecl>(RecordD->getParent());
+
+    llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord;
+    MemberRecord.insert(RecordD->getCanonicalDecl());
+
+    if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord))
+      return false;
   }
 
-  if (!FoundValid) {
-    DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType,
+  DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType,
                                      Qualifier, QualifierRange, R);
+  return true;
+}
+
+static bool
+LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
+                         SourceRange BaseRange, const RecordType *RTy,
+                         SourceLocation OpLoc, const CXXScopeSpec &SS) {
+  RecordDecl *RDecl = RTy->getDecl();
+  if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
+                                  PDiag(diag::err_typecheck_incomplete_tag)
+                                    << BaseRange))
     return true;
+
+  DeclContext *DC = RDecl;
+  if (SS.isSet()) {
+    // If the member name was a qualified-id, look into the
+    // nested-name-specifier.
+    DC = SemaRef.computeDeclContext(SS, false);
+
+    assert(DC && "Cannot handle non-computable dependent contexts in lookup");
+      
+    if (!isa<TypeDecl>(DC)) {
+      SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
+        << DC << SS.getRange();
+      return true;
+    }
   }
 
+  // The record definition is complete, now look up the member.
+  SemaRef.LookupQualifiedName(R, DC);
+
   return false;
 }
 
 Sema::OwningExprResult
-Sema::BuildMemberReferenceExpr(ExprArg BaseArg,
+Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType,
                                SourceLocation OpLoc, bool IsArrow,
                                const CXXScopeSpec &SS,
                                NamedDecl *FirstQualifierInScope,
@@ -2076,38 +2240,52 @@ Sema::BuildMemberReferenceExpr(ExprArg BaseArg,
                                const TemplateArgumentListInfo *TemplateArgs) {
   Expr *Base = BaseArg.takeAs<Expr>();
 
-  if (Base->getType()->isDependentType())
-    return ActOnDependentMemberExpr(ExprArg(*this, Base),
+  if (BaseType->isDependentType())
+    return ActOnDependentMemberExpr(ExprArg(*this, Base), BaseType,
                                     IsArrow, OpLoc,
                                     SS, FirstQualifierInScope,
                                     Name, NameLoc,
                                     TemplateArgs);
 
   LookupResult R(*this, Name, NameLoc, LookupMemberName);
-  OwningExprResult Result =
-    LookupMemberExpr(R, Base, IsArrow, OpLoc,
-                     SS, FirstQualifierInScope,
-                     /*ObjCImpDecl*/ DeclPtrTy());
 
-  if (Result.isInvalid()) {
-    Owned(Base);
-    return ExprError();
-  }
+  // Implicit member accesses.
+  if (!Base) {
+    QualType RecordTy = BaseType;
+    if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
+    if (LookupMemberExprInRecord(*this, R, SourceRange(),
+                                 RecordTy->getAs<RecordType>(),
+                                 OpLoc, SS))
+      return ExprError();
+
+  // Explicit member accesses.
+  } else {
+    OwningExprResult Result =
+      LookupMemberExpr(R, Base, IsArrow, OpLoc,
+                       SS, FirstQualifierInScope,
+                       /*ObjCImpDecl*/ DeclPtrTy());
 
-  if (Result.get())
-    return move(Result);
+    if (Result.isInvalid()) {
+      Owned(Base);
+      return ExprError();
+    }
+
+    if (Result.get())
+      return move(Result);
+  }
 
-  return BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc,
-                                  IsArrow, SS, R, TemplateArgs);
+  return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType,
+                                  OpLoc, IsArrow, SS, R, TemplateArgs);
 }
 
 Sema::OwningExprResult
-Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc,
-                               bool IsArrow, const CXXScopeSpec &SS,
+Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
+                               SourceLocation OpLoc, bool IsArrow,
+                               const CXXScopeSpec &SS,
                                LookupResult &R,
                          const TemplateArgumentListInfo *TemplateArgs) {
   Expr *BaseExpr = Base.takeAs<Expr>();
-  QualType BaseType = BaseExpr->getType();
+  QualType BaseType = BaseExprType;
   if (IsArrow) {
     assert(BaseType->isPointerType());
     BaseType = BaseType->getAs<PointerType>()->getPointeeType();
@@ -2128,7 +2306,8 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc,
                        : BaseType->getAs<RecordType>()->getDecl());
 
     Diag(R.getNameLoc(), diag::err_no_member)
-      << MemberName << DC << BaseExpr->getSourceRange();
+      << MemberName << DC
+      << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
     return ExprError();
   }
 
@@ -2142,15 +2321,15 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc,
   // Construct an unresolved result if we in fact got an unresolved
   // result.
   if (R.isOverloadedResult() || R.isUnresolvableResult()) {
-    bool Dependent = R.isUnresolvableResult();
-    Dependent = Dependent ||
-                UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(),
-                                                        TemplateArgs);
+    bool Dependent =
+      R.isUnresolvableResult() ||
+      UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs);
 
     UnresolvedMemberExpr *MemExpr
       = UnresolvedMemberExpr::Create(Context, Dependent,
                                      R.isUnresolvableResult(),
-                                     BaseExpr, IsArrow, OpLoc,
+                                     BaseExpr, BaseExprType,
+                                     IsArrow, OpLoc,
                                      Qualifier, SS.getRange(),
                                      MemberName, MemberLoc,
                                      TemplateArgs);
@@ -2171,6 +2350,15 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc,
   if (MemberDecl->isInvalidDecl())
     return ExprError();
 
+  // Handle the implicit-member-access case.
+  if (!BaseExpr) {
+    // If this is not an instance member, convert to a non-member access.
+    if (!IsInstanceMember(MemberDecl))
+      return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl);
+
+    BaseExpr = new (Context) CXXThisExpr(SourceLocation(), BaseExprType);
+  }
+
   bool ShouldCheckUse = true;
   if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
     // Don't diagnose the use of a virtual member function unless it's
@@ -2403,31 +2591,9 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
   // Handle field access to simple records.  This also handles access
   // to fields of the ObjC 'id' struct.
   if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
-    RecordDecl *RDecl = RTy->getDecl();
-    if (RequireCompleteType(OpLoc, BaseType,
-                            PDiag(diag::err_typecheck_incomplete_tag)
-                              << BaseExpr->getSourceRange()))
+    if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(),
+                                 RTy, OpLoc, SS))
       return ExprError();
-
-    DeclContext *DC = RDecl;
-    if (SS.isSet()) {
-      // If the member name was a qualified-id, look into the
-      // nested-name-specifier.
-      DC = computeDeclContext(SS, false);
-      
-      if (!isa<TypeDecl>(DC)) {
-        Diag(MemberLoc, diag::err_qualified_member_nonclass)
-          << DC << SS.getRange();
-        return ExprError();
-      }
-
-      // FIXME: If DC is not computable, we should build a
-      // CXXDependentScopeMemberExpr.
-      assert(DC && "Cannot handle non-computable dependent contexts in lookup");
-    }
-
-    // The record definition is complete, now make sure the member is valid.
-    LookupQualifiedName(R, DC);
     return Owned((Expr*) 0);
   }
 
@@ -2739,7 +2905,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
   Expr *Base = BaseArg.takeAs<Expr>();
   OwningExprResult Result(*this);
   if (Base->getType()->isDependentType()) {
-    Result = ActOnDependentMemberExpr(ExprArg(*this, Base),
+    Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(),
                                       IsArrow, OpLoc,
                                       SS, FirstQualifierInScope,
                                       Name, NameLoc,
@@ -2772,8 +2938,8 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
       }
     }
 
-    Result = BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc,
-                                      IsArrow, SS, R, TemplateArgs);
+    Result = BuildMemberReferenceExpr(ExprArg(*this, Base), Base->getType(),
+                                      OpLoc, IsArrow, SS, R, TemplateArgs);
   }
 
   return move(Result);
@@ -3070,16 +3236,16 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
              isa<FunctionTemplateDecl>(*MemE->decls_begin()));
       (void)MemE;
 
-      return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
-                                             CommaLocs, RParenLoc));
+      return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
+                                       CommaLocs, RParenLoc);
     }
 
     // Determine whether this is a call to a member function.
     if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(NakedFn)) {
       NamedDecl *MemDecl = MemExpr->getMemberDecl();
       if (isa<CXXMethodDecl>(MemDecl))
-        return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
-                                               CommaLocs, RParenLoc));
+        return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
+                                         CommaLocs, RParenLoc);
     }
     
     // Determine whether this is a call to a pointer-to-member function.
@@ -3171,13 +3337,28 @@ Sema::ActOnCallExpr(Scope *S, ExprArg fn, SourceLocation LParenLoc,
   } else {
     assert(Fns.size() <= 1 && "overloaded without Overloaded flag");
     if (Fns.empty())
-      NDecl = FDecl = 0;
+      NDecl = 0;
     else {
       NDecl = Fns[0];
-      FDecl = dyn_cast<FunctionDecl>(NDecl);
     }
   }
 
+  return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc);
+}
+
+/// BuildCallExpr - Build a call to a resolved expression, i.e. an
+/// expression not of \p OverloadTy.  The expression should
+/// unary-convert to an expression of function-pointer or
+/// block-pointer type.
+///
+/// \param NDecl the declaration being called, if available
+Sema::OwningExprResult
+Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
+                            SourceLocation LParenLoc,
+                            Expr **Args, unsigned NumArgs,
+                            SourceLocation RParenLoc) {
+  FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
+
   // Promote the function operand.
   UsualUnaryConversions(Fn);
 
index 6ea6a145576d249f27c476d474adb3d90512f262..726e4a01a4dc7b581bbea4b2a8056fdc7e83fc9b 100644 (file)
@@ -5122,7 +5122,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
 /// parameter). The caller needs to validate that the member
 /// expression refers to a member function or an overloaded member
 /// function.
-Sema::ExprResult
+Sema::OwningExprResult
 Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
                                 SourceLocation LParenLoc, Expr **Args,
                                 unsigned NumArgs, SourceLocation *CommaLocs,
@@ -5131,22 +5131,35 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
   // argument and the member function we're referring to.
   Expr *NakedMemExpr = MemExprE->IgnoreParens();
   
-  // Extract the object argument.
-  Expr *ObjectArg;
-
   MemberExpr *MemExpr;
   CXXMethodDecl *Method = 0;
   if (isa<MemberExpr>(NakedMemExpr)) {
     MemExpr = cast<MemberExpr>(NakedMemExpr);
-    ObjectArg = MemExpr->getBase();
     Method = cast<CXXMethodDecl>(MemExpr->getMemberDecl());
   } else {
     UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr);
-    ObjectArg = UnresExpr->getBase();
+
+    // Mock up an object argument.
+    Expr *ObjectArg;
+    if (UnresExpr->isImplicitAccess()) {
+      // It would be nice to avoid creating this, but the overload APIs are written
+      // to work on expressions.
+      ObjectArg = new(Context) CXXThisExpr(SourceLocation(),
+                                           UnresExpr->getBaseType());
+    } else {
+      ObjectArg = UnresExpr->getBase();
+    }
 
     // Add overload candidates
     OverloadCandidateSet CandidateSet;
 
+    // FIXME: avoid copy.
+    TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
+    if (UnresExpr->hasExplicitTemplateArgs()) {
+      UnresExpr->copyTemplateArgumentsInto(TemplateArgsBuffer);
+      TemplateArgs = &TemplateArgsBuffer;
+    }
+
     for (UnresolvedMemberExpr::decls_iterator I = UnresExpr->decls_begin(),
            E = UnresExpr->decls_end(); I != E; ++I) {
 
@@ -5156,20 +5169,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
       if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
         // If explicit template arguments were provided, we can't call a
         // non-template member function.
-        if (UnresExpr->hasExplicitTemplateArgs())
+        if (TemplateArgs)
           continue;
         
         AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
                            /*SuppressUserConversions=*/false);
       } else {
-        // FIXME: avoid copy.
-        TemplateArgumentListInfo TemplateArgs;
-        if (UnresExpr->hasExplicitTemplateArgs())
-          UnresExpr->copyTemplateArgumentsInto(TemplateArgs);
-
         AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func),
-                                   (UnresExpr->hasExplicitTemplateArgs()
-                                      ? &TemplateArgs : 0),
+                                   TemplateArgs,
                                    ObjectArg, Args, NumArgs,
                                    CandidateSet,
                                    /*SuppressUsedConversions=*/false);
@@ -5190,14 +5197,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
         << DeclName << MemExprE->getSourceRange();
       PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
       // FIXME: Leaking incoming expressions!
-      return true;
+      return ExprError();
 
     case OR_Ambiguous:
       Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call)
         << DeclName << MemExprE->getSourceRange();
       PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
       // FIXME: Leaking incoming expressions!
-      return true;
+      return ExprError();
 
     case OR_Deleted:
       Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call)
@@ -5205,16 +5212,29 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
         << DeclName << MemExprE->getSourceRange();
       PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
       // FIXME: Leaking incoming expressions!
-      return true;
+      return ExprError();
     }
 
     MemExprE = FixOverloadedFunctionReference(MemExprE, Method);
+
+    // Clean up the 'this' expression we created above; FixOFR doesn't
+    // actually use it.
+    if (UnresExpr->isImplicitAccess())
+      Owned(ObjectArg);
+    
+    // If overload resolution picked a static member, build a
+    // non-member call based on that function.
+    if (Method->isStatic()) {
+      return BuildResolvedCallExpr(MemExprE, Method, LParenLoc,
+                                   Args, NumArgs, RParenLoc);
+    }
+
     MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens());
   }
 
   assert(Method && "Member call to something that isn't a method?");
   ExprOwningPtr<CXXMemberCallExpr>
-    TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExpr, Args,
+    TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExprE, Args,
                                                   NumArgs,
                                   Method->getResultType().getNonReferenceType(),
                                   RParenLoc));
@@ -5222,24 +5242,25 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
   // Check for a valid return type.
   if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(), 
                           TheCall.get(), Method))
-    return true;
+    return ExprError();
   
   // Convert the object argument (for a non-static member function call).
+  Expr *ObjectArg = MemExpr->getBase();
   if (!Method->isStatic() &&
       PerformObjectArgumentInitialization(ObjectArg, Method))
-    return true;
+    return ExprError();
   MemExpr->setBase(ObjectArg);
 
   // Convert the rest of the arguments
   const FunctionProtoType *Proto = cast<FunctionProtoType>(Method->getType());
   if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs,
                               RParenLoc))
-    return true;
+    return ExprError();
 
   if (CheckFunctionCall(Method, TheCall.get()))
-    return true;
+    return ExprError();
 
-  return MaybeBindToTemporary(TheCall.release()).release();
+  return MaybeBindToTemporary(TheCall.release());
 }
 
 /// BuildCallToObjectOfClassType - Build a call to an object of class
@@ -5632,19 +5653,11 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
   } 
 
   if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
+    // FIXME: avoid copy.
+    TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
     if (ULE->hasExplicitTemplateArgs()) {
-      // FIXME: avoid copy.
-      TemplateArgumentListInfo TemplateArgs;
-      if (ULE->hasExplicitTemplateArgs())
-        ULE->copyTemplateArgumentsInto(TemplateArgs);
-
-      return DeclRefExpr::Create(Context,
-                                 ULE->getQualifier(),
-                                 ULE->getQualifierRange(),
-                                 Fn,
-                                 ULE->getNameLoc(),
-                                 Fn->getType(),
-                                 &TemplateArgs);
+      ULE->copyTemplateArgumentsInto(TemplateArgsBuffer);
+      TemplateArgs = &TemplateArgsBuffer;
     }
 
     return DeclRefExpr::Create(Context,
@@ -5652,23 +5665,43 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
                                ULE->getQualifierRange(),
                                Fn,
                                ULE->getNameLoc(),
-                               Fn->getType());
+                               Fn->getType(),
+                               TemplateArgs);
   }
 
   if (UnresolvedMemberExpr *MemExpr = dyn_cast<UnresolvedMemberExpr>(E)) {
     // FIXME: avoid copy.
-    TemplateArgumentListInfo TemplateArgs;
-    if (MemExpr->hasExplicitTemplateArgs())
-      MemExpr->copyTemplateArgumentsInto(TemplateArgs);
+    TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
+    if (MemExpr->hasExplicitTemplateArgs()) {
+      MemExpr->copyTemplateArgumentsInto(TemplateArgsBuffer);
+      TemplateArgs = &TemplateArgsBuffer;
+    }
+
+    Expr *Base;
+
+    // If we're filling in 
+    if (MemExpr->isImplicitAccess()) {
+      if (cast<CXXMethodDecl>(Fn)->isStatic()) {
+        return DeclRefExpr::Create(Context,
+                                   MemExpr->getQualifier(),
+                                   MemExpr->getQualifierRange(),
+                                   Fn,
+                                   MemExpr->getMemberLoc(),
+                                   Fn->getType(),
+                                   TemplateArgs);
+      } else
+        Base = new (Context) CXXThisExpr(SourceLocation(),
+                                         MemExpr->getBaseType());
+    } else
+      Base = MemExpr->getBase()->Retain();
 
-    return MemberExpr::Create(Context, MemExpr->getBase()->Retain(),
+    return MemberExpr::Create(Context, Base,
                               MemExpr->isArrow(), 
                               MemExpr->getQualifier(), 
                               MemExpr->getQualifierRange(),
                               Fn, 
                               MemExpr->getMemberLoc(),
-                              (MemExpr->hasExplicitTemplateArgs()
-                                 ? &TemplateArgs : 0),
+                              TemplateArgs,
                               Fn->getType());
   }
   
index f47577e9097ea909af6054ec423a4c77883c7138..5f5d891a2264df49db4b7b71568b1326d4ff9b0e 100644 (file)
@@ -361,13 +361,13 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
   QualType ThisType;
   if (CheckForImplicitMember &&
       IsImplicitDependentMemberReference(*this, Qualifier, ThisType)) {
-    Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
-
     // Since the 'this' expression is synthesized, we don't need to
     // perform the double-lookup check.
     NamedDecl *FirstQualifierInScope = 0;
 
-    return Owned(CXXDependentScopeMemberExpr::Create(Context, This, true,
+    return Owned(CXXDependentScopeMemberExpr::Create(Context,
+                                                     /*This*/ 0, ThisType,
+                                                     /*IsArrow*/ true,
                                                      /*Op*/ SourceLocation(),
                                                      Qualifier, SS.getRange(),
                                                      FirstQualifierInScope,
index 28b21740356417350aa695101d4c7ccdd8116bc4..145e3c70a64a79d44635b078dcf2e3396a49f255 100644 (file)
@@ -863,11 +863,14 @@ public:
       SS.setScopeRep(Qualifier);
     }
 
+    QualType BaseType = ((Expr*) Base.get())->getType();
+
     DeclarationName Name
       = SemaRef.Context.DeclarationNames.getCXXDestructorName(
                                SemaRef.Context.getCanonicalType(DestroyedType));
 
-    return getSema().BuildMemberReferenceExpr(move(Base), OperatorLoc, isArrow,
+    return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
+                                              OperatorLoc, isArrow,
                                               SS, /*FIXME: FirstQualifier*/ 0,
                                               Name, DestroyedTypeLoc,
                                               /*TemplateArgs*/ 0);
@@ -964,7 +967,11 @@ public:
       SS.setScopeRep(Qualifier);
     }
 
-    return getSema().BuildMemberReferenceExpr(move(Base), OpLoc, isArrow,
+    QualType BaseType = ((Expr*) Base.get())->getType();
+
+    // FIXME: wait, this is re-performing lookup?
+    return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
+                                              OpLoc, isArrow,
                                               SS, FirstQualifierInScope,
                                               Member->getDeclName(), MemberLoc,
                                               ExplicitTemplateArgs);
@@ -1042,8 +1049,10 @@ public:
                                                SourceLocation OpLoc,
                                                SourceLocation AccessorLoc,
                                                IdentifierInfo &Accessor) {
+
     CXXScopeSpec SS;
-    return getSema().BuildMemberReferenceExpr(move(Base),
+    QualType BaseType = ((Expr*) Base.get())->getType();
+    return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
                                               OpLoc, /*IsArrow*/ false,
                                               SS, /*FirstQualifierInScope*/ 0,
                                               DeclarationName(&Accessor),
@@ -1522,6 +1531,7 @@ public:
   /// By default, performs semantic analysis to build the new expression.
   /// Subclasses may override this routine to provide different behavior.
   OwningExprResult RebuildCXXDependentScopeMemberExpr(ExprArg BaseE,
+                                                  QualType BaseType,
                                                   bool IsArrow,
                                                   SourceLocation OperatorLoc,
                                               NestedNameSpecifier *Qualifier,
@@ -1534,7 +1544,8 @@ public:
     SS.setRange(QualifierRange);
     SS.setScopeRep(Qualifier);
 
-    return SemaRef.BuildMemberReferenceExpr(move(BaseE), OperatorLoc, IsArrow,
+    return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType,
+                                            OperatorLoc, IsArrow,
                                             SS, FirstQualifierInScope,
                                             Name, MemberLoc, TemplateArgs);
   }
@@ -1544,19 +1555,19 @@ public:
   /// By default, performs semantic analysis to build the new expression.
   /// Subclasses may override this routine to provide different behavior.
   OwningExprResult RebuildUnresolvedMemberExpr(ExprArg BaseE,
+                                               QualType BaseType,
                                                SourceLocation OperatorLoc,
                                                bool IsArrow,
                                                NestedNameSpecifier *Qualifier,
                                                SourceRange QualifierRange,
                                                LookupResult &R,
                                 const TemplateArgumentListInfo *TemplateArgs) {
-    OwningExprResult Base = move(BaseE);
-
     CXXScopeSpec SS;
     SS.setRange(QualifierRange);
     SS.setScopeRep(Qualifier);
 
-    return SemaRef.BuildMemberReferenceExpr(move(Base), OperatorLoc, IsArrow,
+    return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType,
+                                            OperatorLoc, IsArrow,
                                             SS, R, TemplateArgs);
   }
 
@@ -4819,18 +4830,32 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
                                                      CXXDependentScopeMemberExpr *E,
                                                      bool isAddressOfOperand) {
   // Transform the base of the expression.
-  OwningExprResult Base = getDerived().TransformExpr(E->getBase());
-  if (Base.isInvalid())
-    return SemaRef.ExprError();
+  OwningExprResult Base(SemaRef, (Expr*) 0);
+  Expr *OldBase;
+  QualType BaseType;
+  QualType ObjectType;
+  if (!E->isImplicitAccess()) {
+    OldBase = E->getBase();
+    Base = getDerived().TransformExpr(OldBase);
+    if (Base.isInvalid())
+      return SemaRef.ExprError();
 
-  // Start the member reference and compute the object's type.
-  Sema::TypeTy *ObjectType = 0;
-  Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
-                                              E->getOperatorLoc(),
+    // Start the member reference and compute the object's type.
+    Sema::TypeTy *ObjectTy = 0;
+    Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
+                                                E->getOperatorLoc(),
                                       E->isArrow()? tok::arrow : tok::period,
-                                              ObjectType);
-  if (Base.isInvalid())
-    return SemaRef.ExprError();
+                                                ObjectTy);
+    if (Base.isInvalid())
+      return SemaRef.ExprError();
+
+    ObjectType = QualType::getFromOpaquePtr(ObjectTy);
+    BaseType = ((Expr*) Base.get())->getType();
+  } else {
+    OldBase = 0;
+    BaseType = getDerived().TransformType(E->getBaseType());
+    ObjectType = BaseType->getAs<PointerType>()->getPointeeType();
+  }
 
   // Transform the first part of the nested-name-specifier that qualifies
   // the member name.
@@ -4843,29 +4868,31 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
   if (E->getQualifier()) {
     Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
                                                       E->getQualifierRange(),
-                                      QualType::getFromOpaquePtr(ObjectType),
-                                                        FirstQualifierInScope);
+                                                      ObjectType,
+                                                      FirstQualifierInScope);
     if (!Qualifier)
       return SemaRef.ExprError();
   }
 
   DeclarationName Name
     = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc(),
-                                       QualType::getFromOpaquePtr(ObjectType));
+                                            ObjectType);
   if (!Name)
     return SemaRef.ExprError();
 
-  if (!E->hasExplicitTemplateArgumentList()) {
+  if (!E->hasExplicitTemplateArgs()) {
     // This is a reference to a member without an explicitly-specified
     // template argument list. Optimize for this common case.
     if (!getDerived().AlwaysRebuild() &&
-        Base.get() == E->getBase() &&
+        Base.get() == OldBase &&
+        BaseType == E->getBaseType() &&
         Qualifier == E->getQualifier() &&
         Name == E->getMember() &&
         FirstQualifierInScope == E->getFirstQualifierFoundInScope())
       return SemaRef.Owned(E->Retain());
 
     return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base),
+                                                       BaseType,
                                                        E->isArrow(),
                                                        E->getOperatorLoc(),
                                                        Qualifier,
@@ -4885,6 +4912,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr(
   }
 
   return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base),
+                                                     BaseType,
                                                      E->isArrow(),
                                                      E->getOperatorLoc(),
                                                      Qualifier,
@@ -4900,9 +4928,16 @@ Sema::OwningExprResult
 TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old,
                                                       bool isAddressOfOperand) {
   // Transform the base of the expression.
-  OwningExprResult Base = getDerived().TransformExpr(Old->getBase());
-  if (Base.isInvalid())
-    return SemaRef.ExprError();
+  OwningExprResult Base(SemaRef, (Expr*) 0);
+  QualType BaseType;
+  if (!Old->isImplicitAccess()) {
+    Base = getDerived().TransformExpr(Old->getBase());
+    if (Base.isInvalid())
+      return SemaRef.ExprError();
+    BaseType = ((Expr*) Base.get())->getType();
+  } else {
+    BaseType = getDerived().TransformType(Old->getBaseType());
+  }
 
   NestedNameSpecifier *Qualifier = 0;
   if (Old->getQualifier()) {
@@ -4951,6 +4986,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old,
   }
   
   return getDerived().RebuildUnresolvedMemberExpr(move(Base),
+                                                  BaseType,
                                                   Old->getOperatorLoc(),
                                                   Old->isArrow(),
                                                   Qualifier,
index 2351d882f9c2cbf4dfe6a8fc671035a5d4460840..231e2812f666938bbf5b126653d36a5862f80473 100644 (file)
@@ -95,9 +95,7 @@ struct X0 : X0Base {
 template<typename U>
 struct X1 : X0<U> {
   int &f2() { 
-    // FIXME: We should be able to do this lookup and diagnose the error
-    // *despite* the fact that we can't decide the relationship yet.
-    return X0Base::f(); // expected-FIXME-error{{call to non-static member function without an object argument}}
+    return X0Base::f();
   }
 };
 
index a07f05ca78ee583afcfe33873accfedc9fdabb36..ab57950acff2ef3b7e5af12296f3efb2e592bb9f 100644 (file)
@@ -18,3 +18,14 @@ namespace test1 {
     }
   };
 }
+
+namespace test2 {
+  class Impl {
+    int foo();
+  };
+  template <class T> class Magic : public Impl {
+    int foo() {
+      return Impl::foo();
+    }
+  };
+}