[cfe-commits] r80167 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/AST/ExprCXX.h include/clang/AST/StmtNodes.def lib/AST/Expr.cpp lib/AST/StmtPrinter.cpp lib/AST/StmtProfile.cpp lib/Analysis/GRExprEngine.cpp lib/CodeGen/CGCXX.cpp lib/CodeGen/CGExpr.cpp lib/Sema/SemaChecking.cpp lib/Sema/SemaExpr.cpp lib/Sema/TreeTransform.h test/CXX/class.derived/class.virtual/p12.cpp

Douglas Gregor dgregor at apple.com
Wed Aug 26 15:36:53 PDT 2009


Author: dgregor
Date: Wed Aug 26 17:36:53 2009
New Revision: 80167

URL: http://llvm.org/viewvc/llvm-project?rev=80167&view=rev
Log:
When a member reference expression includes a qualifier on the member
name, e.g.,
  
  x->Base::f()

retain the qualifier (and its source range information) in a new
subclass of MemberExpr called CXXQualifiedMemberExpr. Provide
construction, transformation, profiling, printing, etc., for this new
expression type.

When a virtual function is called via a qualified name, don't emit a
virtual call. Instead, call that function directly. Mike, could you
add a CodeGen test for this, too?


Added:
    cfe/trunk/test/CXX/class.derived/class.virtual/p12.cpp
Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/AST/StmtNodes.def
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtProfile.cpp
    cfe/trunk/lib/Analysis/GRExprEngine.cpp
    cfe/trunk/lib/CodeGen/CGCXX.cpp
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/TreeTransform.h

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

==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Wed Aug 26 17:36:53 2009
@@ -33,6 +33,7 @@
   class BlockDecl;
   class CXXOperatorCallExpr;
   class CXXMemberCallExpr;
+  class CXXQualifiedMemberExpr;
 
 /// Expr - This represents one expression.  Note that Expr's are subclasses of
 /// Stmt.  This allows an expression to be transparently used any place a Stmt
@@ -1054,6 +1055,14 @@
   
   /// IsArrow - True if this is "X->F", false if this is "X.F".
   bool IsArrow;
+  
+protected:
+  MemberExpr(StmtClass SC, Expr *base, bool isarrow, NamedDecl *memberdecl, 
+             SourceLocation l, QualType ty) 
+    : Expr(SC, ty, 
+           base->isTypeDependent(), base->isValueDependent()),
+  Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow) {}
+  
 public:
   MemberExpr(Expr *base, bool isarrow, NamedDecl *memberdecl, SourceLocation l,
              QualType ty) 
@@ -1094,9 +1103,11 @@
   virtual SourceLocation getExprLoc() const { return MemberLoc; }
 
   static bool classof(const Stmt *T) { 
-    return T->getStmtClass() == MemberExprClass; 
+    return T->getStmtClass() == MemberExprClass ||
+      T->getStmtClass() == CXXQualifiedMemberExprClass;
   }
   static bool classof(const MemberExpr *) { return true; }
+  static bool classof(const CXXQualifiedMemberExpr *) { return true; }
   
   // Iterators
   virtual child_iterator child_begin();

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

==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Wed Aug 26 17:36:53 2009
@@ -1285,7 +1285,41 @@
   virtual child_iterator child_end();
 };
 
-/// \brief 
+/// \brief Represents a C++ member access expression that was written using
+/// a qualified name, e.g., "x->Base::f()".
+class CXXQualifiedMemberExpr : public MemberExpr {
+  /// QualifierRange - The source range that covers the
+  /// nested-name-specifier.
+  SourceRange QualifierRange;
+  
+  /// \brief The nested-name-specifier that qualifies this declaration
+  /// name.
+  NestedNameSpecifier *Qualifier;
+  
+public:
+  CXXQualifiedMemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *Qual,
+                         SourceRange QualRange, NamedDecl *memberdecl, 
+                         SourceLocation l, QualType ty) 
+    : MemberExpr(CXXQualifiedMemberExprClass, base, isarrow, memberdecl, l, ty),
+      QualifierRange(QualRange), Qualifier(Qual) { }
+
+  /// \brief Retrieve the source range of the nested-name-specifier that 
+  /// qualifies the member name.
+  SourceRange getQualifierRange() const { return QualifierRange; }
+  
+  /// \brief Retrieve the nested-name-specifier that qualifies the
+  /// member reference expression.
+  NestedNameSpecifier *getQualifier() const { return Qualifier; }
+  
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXQualifiedMemberExprClass;
+  }
+  static bool classof(const CXXQualifiedMemberExpr *) { return true; }  
+};
+  
+/// \brief Represents a C++ member access expression where the actual member
+/// referenced could not be resolved, e.g., because the base expression or the
+/// member name was dependent.
 class CXXUnresolvedMemberExpr : public Expr {
   /// \brief The expression for the base pointer or class reference,
   /// e.g., the \c x in x.f.

Modified: cfe/trunk/include/clang/AST/StmtNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtNodes.def?rev=80167&r1=80166&r2=80167&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/StmtNodes.def (original)
+++ cfe/trunk/include/clang/AST/StmtNodes.def Wed Aug 26 17:36:53 2009
@@ -134,6 +134,7 @@
 EXPR(CXXExprWithTemporaries , Expr)
 EXPR(CXXTemporaryObjectExpr , CXXConstructExpr)
 EXPR(CXXUnresolvedConstructExpr, Expr)
+EXPR(CXXQualifiedMemberExpr, MemberExpr)
 EXPR(CXXUnresolvedMemberExpr, Expr)
 
 // Obj-C Expressions.

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

==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Wed Aug 26 17:36:53 2009
@@ -497,6 +497,7 @@
   }
 
   case MemberExprClass:
+  case CXXQualifiedMemberExprClass:
     // If the base pointer or element is to a volatile pointer/field, accessing
     // it is a side effect.
     if (getType().isVolatileQualified())
@@ -684,7 +685,8 @@
       return LV_Valid;
     break;
   }
-  case MemberExprClass: { 
+  case MemberExprClass: 
+  case CXXQualifiedMemberExprClass: { 
     const MemberExpr *m = cast<MemberExpr>(this);
     if (Ctx.getLangOptions().CPlusPlus) { // C++ [expr.ref]p4:
       NamedDecl *Member = m->getMemberDecl();
@@ -948,7 +950,8 @@
       return true;
     return false;
   }
-  case MemberExprClass: {
+  case MemberExprClass:
+  case CXXQualifiedMemberExprClass: {
     const MemberExpr *M = cast<MemberExpr>(this);
     return !M->isArrow() && M->getBase()->hasGlobalStorage();
   }
@@ -992,7 +995,8 @@
     }
     return false;
   }
-  case MemberExprClass: {
+  case MemberExprClass: 
+  case CXXQualifiedMemberExprClass: {
     const MemberExpr *M = cast<MemberExpr>(this);
     return M->getBase()->isOBJCGCCandidate(Ctx);
   }

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

==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Wed Aug 26 17:36:53 2009
@@ -1126,6 +1126,16 @@
   OS << ")";
 }
 
+void StmtPrinter::VisitCXXQualifiedMemberExpr(CXXQualifiedMemberExpr *Node) {
+  // FIXME: Suppress printing implicit bases (like "this")
+  PrintExpr(Node->getBase());
+  OS << (Node->isArrow() ? "->" : ".");
+  // FIXME: Suppress printing references to unnamed objects
+  // representing anonymous unions/structs
+  Node->getQualifier()->print(OS, Policy);
+  OS << Node->getMemberDecl()->getNameAsString();
+}
+
 void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) {
   PrintExpr(Node->getBase());
   OS << (Node->isArrow() ? "->" : ".");

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

==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Wed Aug 26 17:36:53 2009
@@ -546,6 +546,11 @@
   VisitType(S->getTypeAsWritten());
 }
 
+void StmtProfiler::VisitCXXQualifiedMemberExpr(CXXQualifiedMemberExpr *S) {
+  VisitMemberExpr(S);
+  VisitNestedNameSpecifier(S->getQualifier());
+}
+
 void StmtProfiler::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *S) {
   VisitExpr(S);
   ID.AddBoolean(S->isArrow());

Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=80167&r1=80166&r2=80167&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Wed Aug 26 17:36:53 2009
@@ -408,6 +408,7 @@
       break;
       
     case Stmt::MemberExprClass:
+    case Stmt::CXXQualifiedMemberExprClass:
       VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst, false);
       break;
       
@@ -515,6 +516,7 @@
       return;
       
     case Stmt::MemberExprClass:
+    case Stmt::CXXQualifiedMemberExprClass:
       VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true);
       return;
       

Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=80167&r1=80166&r2=80167&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Wed Aug 26 17:36:53 2009
@@ -212,11 +212,13 @@
     This = BaseLV.getAddress();
   }
 
+  // C++ [class.virtual]p12:
+  //   Explicit qualification with the scope operator (5.1) suppresses the 
+  //   virtual call mechanism.
   llvm::Value *Callee;
-  // FIXME: Someone needs to keep track of the qualifications.
-  if (MD->isVirtual() /* && !ME->NotQualified() */)
+  if (MD->isVirtual() && !isa<CXXQualifiedMemberExpr>(CE)) {
     Callee = BuildVirtualCall(MD, This, Ty);
-  else
+  } else
     Callee = CGM.GetAddrOfFunction(GlobalDecl(MD), Ty);
   
   return EmitCXXMemberCall(MD, Callee, This, 

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=80167&r1=80166&r2=80167&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Wed Aug 26 17:36:53 2009
@@ -240,7 +240,9 @@
     return EmitArraySubscriptExpr(cast<ArraySubscriptExpr>(E));
   case Expr::ExtVectorElementExprClass:
     return EmitExtVectorElementExpr(cast<ExtVectorElementExpr>(E));
-  case Expr::MemberExprClass: return EmitMemberExpr(cast<MemberExpr>(E));
+  case Expr::MemberExprClass: 
+  case Stmt::CXXQualifiedMemberExprClass:
+    return EmitMemberExpr(cast<MemberExpr>(E));
   case Expr::CompoundLiteralExprClass:
     return EmitCompoundLiteralLValue(cast<CompoundLiteralExpr>(E));
   case Expr::ConditionalOperatorClass:

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Aug 26 17:36:53 2009
@@ -1421,7 +1421,8 @@
   }
   
   // Accesses to members are potential references to data on the stack.
-  case Stmt::MemberExprClass: {
+  case Stmt::MemberExprClass: 
+  case Stmt::CXXQualifiedMemberExprClass: {
     MemberExpr *M = cast<MemberExpr>(E);
       
     // Check for indirect access.  We only want direct field accesses.

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Aug 26 17:36:53 2009
@@ -631,6 +631,7 @@
     if (BaseAddrSpace != MemberType.getAddressSpace())
       MemberType = Context.getAddrSpaceQualType(MemberType, BaseAddrSpace);
     MarkDeclarationReferenced(Loc, *FI);
+    // FIXME: Might this end up being a qualified name?
     Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI,
                                       OpLoc, MemberType);
     BaseObjectIsPointer = false;
@@ -874,6 +875,19 @@
   return false;
 }
 
+/// \brief Build a MemberExpr or CXXQualifiedMemberExpr, as appropriate.
+static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, 
+                                   const CXXScopeSpec *SS, NamedDecl *Member, 
+                                   SourceLocation Loc, QualType Ty) {
+  if (SS && SS->isSet())
+    return new (C) CXXQualifiedMemberExpr(Base, isArrow, 
+                                          (NestedNameSpecifier *)SS->getScopeRep(),
+                                          SS->getRange(),
+                                          Member, Loc, Ty);
+  
+  return new (C) MemberExpr(Base, isArrow, Member, Loc, Ty);
+}
+
 /// \brief Complete semantic analysis for a reference to the given declaration.
 Sema::OwningExprResult
 Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
@@ -985,8 +999,8 @@
             return ExprError();
           if (DiagnoseUseOfDecl(D, Loc))
             return ExprError();
-          return Owned(new (Context) MemberExpr(This, true, D,
-                                                Loc, MemberType));
+          return Owned(BuildMemberExpr(Context, This, true, SS, D,
+                                       Loc, MemberType));
         }
       }
     }
@@ -1953,7 +1967,7 @@
     return FindMethodInNestedImplementations(IFace->getSuperClass(), Sel);
   return Method;
 }
-
+                       
 Action::OwningExprResult 
 Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
                                tok::TokenKind OpKind, SourceLocation MemberLoc,
@@ -2112,37 +2126,37 @@
       MarkDeclarationReferenced(MemberLoc, FD);
       if (PerformObjectMemberConversion(BaseExpr, FD))
         return ExprError();
-      return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, FD,
-                                            MemberLoc, MemberType));
+      return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS, 
+                                   FD, MemberLoc, MemberType));
     }
     
     if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) {
       MarkDeclarationReferenced(MemberLoc, MemberDecl);
-      return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
-                                            Var, MemberLoc,
-                                         Var->getType().getNonReferenceType()));
+      return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+                                   Var, MemberLoc,
+                                   Var->getType().getNonReferenceType()));
     }
     if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) {
       MarkDeclarationReferenced(MemberLoc, MemberDecl);
-      return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
-                                            MemberFn, MemberLoc,
-                                            MemberFn->getType()));
+      return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+                                   MemberFn, MemberLoc,
+                                   MemberFn->getType()));
     }
     if (FunctionTemplateDecl *FunTmpl 
           = dyn_cast<FunctionTemplateDecl>(MemberDecl)) {
       MarkDeclarationReferenced(MemberLoc, MemberDecl);
-      return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
-                                            FunTmpl, MemberLoc,
-                                            Context.OverloadTy));
+      return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+                                   FunTmpl, MemberLoc,
+                                   Context.OverloadTy));
     }
     if (OverloadedFunctionDecl *Ovl
           = dyn_cast<OverloadedFunctionDecl>(MemberDecl))
-      return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl,
-                                            MemberLoc, Context.OverloadTy));
+      return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+                                   Ovl, MemberLoc, Context.OverloadTy));
     if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) {
       MarkDeclarationReferenced(MemberLoc, MemberDecl);
-      return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow,
-                                            Enum, MemberLoc, Enum->getType()));
+      return Owned(BuildMemberExpr(Context, BaseExpr, OpKind == tok::arrow, SS,
+                                   Enum, MemberLoc, Enum->getType()));
     }
     if (isa<TypeDecl>(MemberDecl))
       return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type)
@@ -4802,6 +4816,7 @@
   case Stmt::QualifiedDeclRefExprClass:
     return cast<DeclRefExpr>(E)->getDecl();
   case Stmt::MemberExprClass:
+  case Stmt::CXXQualifiedMemberExprClass:
     // If this is an arrow operator, the address is an offset from
     // the base's value, so the object the base refers to is
     // irrelevant.

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

==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Wed Aug 26 17:36:53 2009
@@ -1421,6 +1421,28 @@
                                                RParenLoc);
   }
   
+  /// \brief Build a new qualified member access expression.
+  /// 
+  /// By default, performs semantic analysis to build the new expression.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningExprResult RebuildCXXQualifiedMemberExpr(ExprArg Base, 
+                                                 SourceLocation OpLoc,
+                                                 bool isArrow, 
+                                                NestedNameSpecifier *Qualifier,
+                                                 SourceRange QualifierRange,
+                                                 SourceLocation MemberLoc,
+                                                 NamedDecl *Member) {
+    CXXScopeSpec SS;
+    SS.setRange(QualifierRange);
+    SS.setScopeRep(Qualifier);
+    return getSema().ActOnMemberReferenceExpr(/*Scope=*/0, move(Base), OpLoc,
+                                              isArrow? tok::arrow : tok::period,
+                                              MemberLoc,
+                                              /*FIXME*/*Member->getIdentifier(),
+                                      /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0),
+                                              &SS);
+  }
+  
   /// \brief Build a new member reference expression.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -3992,6 +4014,44 @@
                                                         E->getRParenLoc());
 }
 
+template<typename Derived> 
+Sema::OwningExprResult 
+TreeTransform<Derived>::TransformCXXQualifiedMemberExpr(
+                                                  CXXQualifiedMemberExpr *E) { 
+  OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+  if (Base.isInvalid())
+    return SemaRef.ExprError();
+  
+  NamedDecl *Member 
+    = cast_or_null<NamedDecl>(getDerived().TransformDecl(E->getMemberDecl()));
+  if (!Member)
+    return SemaRef.ExprError();
+ 
+  NestedNameSpecifier *Qualifier
+    = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
+                                                E->getQualifierRange());
+  if (Qualifier == 0)
+    return SemaRef.ExprError();
+
+  if (!getDerived().AlwaysRebuild() &&
+      Base.get() == E->getBase() &&
+      Member == E->getMemberDecl() &&
+      Qualifier == E->getQualifier())
+    return SemaRef.Owned(E->Retain()); 
+ 
+  // FIXME: Bogus source location for the operator
+  SourceLocation FakeOperatorLoc
+    = SemaRef.PP.getLocForEndOfToken(E->getBase()->getSourceRange().getEnd());
+  
+  return getDerived().RebuildCXXQualifiedMemberExpr(move(Base), 
+                                                     FakeOperatorLoc,
+                                                     E->isArrow(),
+                                                     Qualifier,
+                                                     E->getQualifierRange(),
+                                                     E->getMemberLoc(),
+                                                     Member);
+}
+  
 template<typename Derived>
 Sema::OwningExprResult
 TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(

Added: cfe/trunk/test/CXX/class.derived/class.virtual/p12.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.derived/class.virtual/p12.cpp?rev=80167&view=auto

==============================================================================
--- cfe/trunk/test/CXX/class.derived/class.virtual/p12.cpp (added)
+++ cfe/trunk/test/CXX/class.derived/class.virtual/p12.cpp Wed Aug 26 17:36:53 2009
@@ -0,0 +1,19 @@
+// RUN: clang-cc -ast-print %s | FileCheck %s
+
+// CHECK: test12_A::foo()
+struct test12_A {
+  virtual void foo();
+  
+  void bar() {
+    test12_A::foo();
+  }
+};
+
+// CHECK: xp->test24_B::wibble()
+struct test24_B {
+  virtual void wibble();
+};
+
+void foo(test24_B *xp) {
+  xp->test24_B::wibble();
+}





More information about the cfe-commits mailing list