[cfe-commits] r112258 - in /cfe/trunk: include/clang/AST/ExprCXX.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Parser.h include/clang/Sema/Sema.h lib/AST/ExprClassification.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Sema/SemaAccess.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplateDeduction.cpp test/SemaCXX/member-pointer.cpp

John McCall rjmccall at apple.com
Fri Aug 27 02:08:28 PDT 2010


Author: rjmccall
Date: Fri Aug 27 04:08:28 2010
New Revision: 112258

URL: http://llvm.org/viewvc/llvm-project?rev=112258&view=rev
Log:
Propagate whether an id-expression is the immediate argument of
an '&' expression from the second caller of ActOnIdExpression.

Teach template argument deduction that an overloaded id-expression
doesn't give a valid type for deduction purposes to a non-static
member function unless the expression has the correct syntactic
form.

Teach ActOnIdExpression that it shouldn't try to create implicit
member expressions for '&function', because this isn't a        
permitted form of use for member functions.

Teach CheckAddressOfOperand to diagnose these more carefully.
Some of these cases aren't reachable right now because earlier
diagnostics interrupt them.



Modified:
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ExprClassification.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/SemaAccess.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/test/SemaCXX/member-pointer.cpp

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=112258&r1=112257&r2=112258&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Fri Aug 27 04:08:28 2010
@@ -1440,19 +1440,38 @@
                                 UnresolvedSetIterator End,
                                 const TemplateArgumentListInfo *Args);
 
+  struct FindResult {
+    OverloadExpr *Expression;
+    bool IsAddressOfOperand;
+    bool HasFormOfMemberPointer;
+  };
+
   /// Finds the overloaded expression in the given expression of
   /// OverloadTy.
   ///
-  /// \return the expression (which must be there) and true if it is
-  /// within an address-of operator.
-  static llvm::PointerIntPair<OverloadExpr*,1> find(Expr *E) {
+  /// \return the expression (which must be there) and true if it has
+  /// the particular form of a member pointer expression
+  static FindResult find(Expr *E) {
     assert(E->getType()->isSpecificBuiltinType(BuiltinType::Overload));
 
-    bool op = false;
+    FindResult Result;
+
     E = E->IgnoreParens();
-    if (isa<UnaryOperator>(E))
-      op = true, E = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
-    return llvm::PointerIntPair<OverloadExpr*,1>(cast<OverloadExpr>(E), op);
+    if (isa<UnaryOperator>(E)) {
+      assert(cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf);
+      E = cast<UnaryOperator>(E)->getSubExpr();
+      OverloadExpr *Ovl = cast<OverloadExpr>(E->IgnoreParens());
+
+      Result.HasFormOfMemberPointer = (E == Ovl && Ovl->getQualifier());
+      Result.IsAddressOfOperand = true;
+      Result.Expression = Ovl;
+    } else {
+      Result.HasFormOfMemberPointer = false;
+      Result.IsAddressOfOperand = false;
+      Result.Expression = cast<OverloadExpr>(E);
+    }
+
+    return Result;
   }
 
   /// Gets the naming class of this lookup, if any.

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=112258&r1=112257&r2=112258&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Aug 27 04:08:28 2010
@@ -2127,7 +2127,11 @@
 def ext_typecheck_addrof_void : Extension<
   "ISO C forbids taking the address of an expression of type 'void'">;
 def err_unqualified_pointer_member_function : Error<
-  "must explicitly qualify member function %0 when taking its address">;
+  "must explicitly qualify name of member function when taking its address">;
+def err_invalid_form_pointer_member_function : Error<
+  "cannot create a non-constant pointer to member function">;
+def err_parens_pointer_member_function : Error<
+  "cannot parenthesize the name of a method when forming a member pointer">;
 def err_typecheck_invalid_lvalue_addrof : Error<
   "address expression must be an lvalue or a function designator">;
 def ext_typecheck_addrof_class_temporary : ExtWarn<

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=112258&r1=112257&r2=112258&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Fri Aug 27 04:08:28 2010
@@ -949,6 +949,16 @@
   ExprResult ParseCastExpression(bool isUnaryExpression,
                                        bool isAddressOfOperand = false,
                                        ParsedType TypeOfCast = ParsedType());
+
+  /// Returns true if the next token would start a postfix-expression
+  /// suffix.
+  bool isPostfixExpressionSuffixStart() {
+    tok::TokenKind K = Tok.getKind();
+    return (K == tok::l_square || K == tok::l_paren ||
+            K == tok::period || K == tok::arrow ||
+            K == tok::plusplus || K == tok::minusminus);
+  }
+
   ExprResult ParsePostfixExpressionSuffix(ExprResult LHS);
   ExprResult ParseSizeofAlignofExpression();
   ExprResult ParseBuiltinPrimaryExpression();

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=112258&r1=112257&r2=112258&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Aug 27 04:08:28 2010
@@ -1715,7 +1715,7 @@
                                            Expr *BaseObjectExpr = 0,
                                       SourceLocation OpLoc = SourceLocation());
   ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS,
-                                                   LookupResult &R,
+                                             LookupResult &R,
                                 const TemplateArgumentListInfo *TemplateArgs);
   ExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS,
                                            LookupResult &R,

Modified: cfe/trunk/lib/AST/ExprClassification.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=112258&r1=112257&r2=112258&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprClassification.cpp (original)
+++ cfe/trunk/lib/AST/ExprClassification.cpp Fri Aug 27 04:08:28 2010
@@ -229,6 +229,10 @@
   // In addition, NonTypeTemplateParmDecl derives from VarDecl but isn't an
   // lvalue unless it's a reference type (C++ [temp.param]p6), so we need to
   // special-case this.
+
+  if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())
+    return Cl::CL_MemberFunction;
+
   bool islvalue;
   if (const NonTypeTemplateParmDecl *NTTParm =
         dyn_cast<NonTypeTemplateParmDecl>(D))

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=112258&r1=112257&r2=112258&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Fri Aug 27 04:08:28 2010
@@ -660,6 +660,10 @@
                                               ILoc, PropertyLoc);
       break;
     }
+
+    // Make sure to pass down the right value for isAddressOfOperand.
+    if (isAddressOfOperand && isPostfixExpressionSuffixStart())
+      isAddressOfOperand = false;
    
     // Function designators are allowed to be undeclared (C99 6.5.1p2), so we
     // need to know whether or not this identifier is a function designator or
@@ -668,7 +672,7 @@
     CXXScopeSpec ScopeSpec;
     Name.setIdentifier(&II, ILoc);
     Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, Name, 
-                                    Tok.is(tok::l_paren), false);
+                                    Tok.is(tok::l_paren), isAddressOfOperand);
     break;
   }
   case tok::char_constant:     // constant: character-constant

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=112258&r1=112257&r2=112258&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Fri Aug 27 04:08:28 2010
@@ -416,21 +416,8 @@
 
   // This is only the direct operand of an & operator if it is not
   // followed by a postfix-expression suffix.
-  if (isAddressOfOperand) {
-    switch (Tok.getKind()) {
-    case tok::l_square:
-    case tok::l_paren:
-    case tok::arrow:
-    case tok::period:
-    case tok::plusplus:
-    case tok::minusminus:
-      isAddressOfOperand = false;
-      break;
-
-    default:
-      break;
-    }
-  }
+  if (isAddressOfOperand && isPostfixExpressionSuffixStart())
+    isAddressOfOperand = false;
   
   return Actions.ActOnIdExpression(getCurScope(), SS, Name, Tok.is(tok::l_paren),
                                    isAddressOfOperand);

Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=112258&r1=112257&r2=112258&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Fri Aug 27 04:08:28 2010
@@ -1268,7 +1268,7 @@
       Found.getAccess() == AS_public)
     return AR_accessible;
 
-  OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).getPointer();
+  OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).Expression;
   CXXRecordDecl *NamingClass = Ovl->getNamingClass();
 
   AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found,

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=112258&r1=112257&r2=112258&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Aug 27 04:08:28 2010
@@ -1233,11 +1233,33 @@
   //   member of some class C, the id-expression is transformed into a
   //   class member access expression using (*this) as the
   //   postfix-expression to the left of the . operator.
-  // So if we found a class member with an expression of form other
-  // than &A::foo, we have to try to build an implicit member expr.
+  //
+  // But we don't actually need to do this for '&' operands if R
+  // resolved to a function or overloaded function set, because the
+  // expression is ill-formed if it actually works out to be a
+  // non-static member function:
+  //
+  // C++ [expr.ref]p4:
+  //   Otherwise, if E1.E2 refers to a non-static member function. . .
+  //   [t]he expression can be used only as the left-hand operand of a
+  //   member function call.
+  //
+  // There are other safeguards against such uses, but it's important
+  // to get this right here so that we don't end up making a
+  // spuriously dependent expression if we're inside a dependent
+  // instance method.
   if (!R.empty() && (*R.begin())->isCXXClassMember()) {
-    bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty());
-    if (!isAbstractMemberPointer)
+    bool MightBeImplicitMember;
+    if (!isAddressOfOperand)
+      MightBeImplicitMember = true;
+    else if (!SS.isEmpty())
+      MightBeImplicitMember = false;
+    else if (R.isOverloadedResult())
+      MightBeImplicitMember = false;
+    else
+      MightBeImplicitMember = isa<FieldDecl>(R.getFoundDecl());
+
+    if (MightBeImplicitMember)
       return BuildPossibleImplicitMemberExpr(SS, R, TemplateArgs);
   }
 
@@ -6209,12 +6231,14 @@
 /// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue.
 /// In C++, the operand might be an overloaded function name, in which case
 /// we allow the '&' but retain the overloaded-function type.
-QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
-  // Make sure to ignore parentheses in subsequent checks
-  op = op->IgnoreParens();
-
-  if (op->isTypeDependent())
+QualType Sema::CheckAddressOfOperand(Expr *OrigOp, SourceLocation OpLoc) {
+  if (OrigOp->isTypeDependent())
     return Context.DependentTy;
+  if (OrigOp->getType() == Context.OverloadTy)
+    return Context.OverloadTy;
+
+  // Make sure to ignore parentheses in subsequent checks
+  Expr *op = OrigOp->IgnoreParens();
 
   if (getLangOptions().C99) {
     // Implement C99-only parts of addressof rules.
@@ -6230,32 +6254,41 @@
   NamedDecl *dcl = getPrimaryDecl(op);
   Expr::isLvalueResult lval = op->isLvalue(Context);
 
-  MemberExpr *ME = dyn_cast<MemberExpr>(op);
-  if (lval == Expr::LV_MemberFunction && ME &&
-      isa<CXXMethodDecl>(ME->getMemberDecl())) {
-    ValueDecl *dcl = cast<MemberExpr>(op)->getMemberDecl();
-    // &f where f is a member of the current object, or &o.f, or &p->f
-    // All these are not allowed, and we need to catch them before the dcl
-    // branch of the if, below.
-    Diag(OpLoc, diag::err_unqualified_pointer_member_function)
-        << dcl;
-    // FIXME: Improve this diagnostic and provide a fixit.
-
-    // Now recover by acting as if the function had been accessed qualified.
-    return Context.getMemberPointerType(op->getType(),
-                Context.getTypeDeclType(cast<RecordDecl>(dcl->getDeclContext()))
-                       .getTypePtr());
-  }
-  
   if (lval == Expr::LV_ClassTemporary) {
     Diag(OpLoc, isSFINAEContext()? diag::err_typecheck_addrof_class_temporary
                                  : diag::ext_typecheck_addrof_class_temporary)
       << op->getType() << op->getSourceRange();
     if (isSFINAEContext())
       return QualType();
-  } else if (isa<ObjCSelectorExpr>(op))
+  } else if (isa<ObjCSelectorExpr>(op)) {
     return Context.getPointerType(op->getType());
-  else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) {
+  } else if (lval == Expr::LV_MemberFunction) {
+    // If it's an instance method, make a member pointer.
+    // The expression must have exactly the form &A::foo.
+
+    // If the underlying expression isn't a decl ref, give up.
+    if (!isa<DeclRefExpr>(op)) {
+      Diag(OpLoc, diag::err_invalid_form_pointer_member_function)
+        << OrigOp->getSourceRange();
+      return QualType();
+    }
+    DeclRefExpr *DRE = cast<DeclRefExpr>(op);
+    CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl());
+
+    // The id-expression was parenthesized.
+    if (OrigOp != DRE) {
+      Diag(OpLoc, diag::err_parens_pointer_member_function)
+        << OrigOp->getSourceRange();
+
+    // The method was named without a qualifier.
+    } else if (!DRE->getQualifier()) {
+      Diag(OpLoc, diag::err_unqualified_pointer_member_function)
+        << op->getSourceRange();
+    }
+
+    return Context.getMemberPointerType(op->getType(),
+              Context.getTypeDeclType(MD->getParent()).getTypePtr());
+  } else if (lval != Expr::LV_Valid && lval != Expr::LV_IncompleteVoidType) {
     // C99 6.5.3.2p1
     // The operand must be either an l-value or a function designator
     if (!op->getType()->isFunctionType()) {
@@ -6283,8 +6316,6 @@
     // FIXME: Can LHS ever be null here?
     if (!CheckAddressOfOperand(CO->getTrueExpr(), OpLoc).isNull())
       return CheckAddressOfOperand(CO->getFalseExpr(), OpLoc);
-  } else if (isa<OverloadExpr>(op)) {
-    return Context.OverloadTy;
   } else if (dcl) { // C99 6.5.3.2p1
     // We have an lvalue with a decl. Make sure the decl is not declared
     // with the register storage-class specifier.
@@ -6317,13 +6348,6 @@
                 Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
         }
       }
-    } else if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(dcl)) {
-      // Okay: we can take the address of a function.
-      // As above.
-      if (isa<DeclRefExpr>(op) && cast<DeclRefExpr>(op)->getQualifier() &&
-          MD->isInstance())
-        return Context.getMemberPointerType(op->getType(),
-              Context.getTypeDeclType(MD->getParent()).getTypePtr());
     } else if (!isa<FunctionDecl>(dcl))
       assert(0 && "Unknown/unexpected decl type");
   }

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=112258&r1=112257&r2=112258&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Aug 27 04:08:28 2010
@@ -6222,18 +6222,8 @@
   //     A pointer to member is only formed when an explicit & is used
   //     and its operand is a qualified-id not enclosed in
   //     parentheses.
-  bool HasFormOfMemberPointer = false;
-  OverloadExpr *OvlExpr;
-  {
-    Expr *Tmp = From->IgnoreParens();
-    if (isa<UnaryOperator>(Tmp)) {
-      Tmp = cast<UnaryOperator>(Tmp)->getSubExpr();
-      OvlExpr = cast<OverloadExpr>(Tmp->IgnoreParens());
-      HasFormOfMemberPointer = (Tmp == OvlExpr && OvlExpr->getQualifier());
-    } else {
-      OvlExpr = cast<OverloadExpr>(Tmp);
-    }
-  }
+  OverloadExpr::FindResult Ovl = OverloadExpr::find(From);
+  OverloadExpr *OvlExpr = Ovl.Expression;
   
   // We expect a pointer or reference to function, or a function pointer.
   FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType();
@@ -6247,7 +6237,7 @@
 
   // If the overload expression doesn't have the form of a pointer to
   // member, don't try to convert it to a pointer-to-member type.
-  if (IsMember && !HasFormOfMemberPointer) {
+  if (IsMember && !Ovl.HasFormOfMemberPointer) {
     if (!Complain) return 0;
 
     // TODO: Should we condition this on whether any functions might
@@ -6453,7 +6443,7 @@
   if (From->getType() != Context.OverloadTy)
     return 0;
 
-  OverloadExpr *OvlExpr = OverloadExpr::find(From).getPointer();
+  OverloadExpr *OvlExpr = OverloadExpr::find(From).Expression;
   
   // If we didn't actually find any template-ids, we're done.
   if (!OvlExpr->hasExplicitTemplateArgs())

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=112258&r1=112257&r2=112258&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Fri Aug 27 04:08:28 2010
@@ -1494,14 +1494,22 @@
   return TDK_Success;
 }
 
+/// Gets the type of a function for template-argument-deducton
+/// purposes when it's considered as part of an overload set.
 static QualType GetTypeOfFunction(ASTContext &Context,
-                                  bool isAddressOfOperand,
+                                  const OverloadExpr::FindResult &R,
                                   FunctionDecl *Fn) {
-  if (!isAddressOfOperand) return Fn->getType();
   if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn))
-    if (Method->isInstance())
+    if (Method->isInstance()) {
+      // An instance method that's referenced in a form that doesn't
+      // look like a member pointer is just invalid.
+      if (!R.HasFormOfMemberPointer) return QualType();
+
       return Context.getMemberPointerType(Fn->getType(),
                Context.getTypeDeclType(Method->getParent()).getTypePtr());
+    }
+
+  if (!R.IsAddressOfOperand) return Fn->getType();
   return Context.getPointerType(Fn->getType());
 }
 
@@ -1512,10 +1520,10 @@
 static QualType
 ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
                             Expr *Arg, QualType ParamType) {
-  llvm::PointerIntPair<OverloadExpr*,1> R = OverloadExpr::find(Arg);
+  
+  OverloadExpr::FindResult R = OverloadExpr::find(Arg);
 
-  bool isAddressOfOperand = bool(R.getInt());
-  OverloadExpr *Ovl = R.getPointer();
+  OverloadExpr *Ovl = R.Expression;
 
   // If there were explicit template arguments, we can only find
   // something via C++ [temp.arg.explicit]p3, i.e. if the arguments
@@ -1524,7 +1532,7 @@
     // But we can still look for an explicit specialization.
     if (FunctionDecl *ExplicitSpec
           = S.ResolveSingleFunctionTemplateSpecialization(Ovl))
-      return GetTypeOfFunction(S.Context, isAddressOfOperand, ExplicitSpec);
+      return GetTypeOfFunction(S.Context, R, ExplicitSpec);
     return QualType();
   }
 
@@ -1549,7 +1557,8 @@
       return QualType();
 
     FunctionDecl *Fn = cast<FunctionDecl>(D);
-    QualType ArgType = GetTypeOfFunction(S.Context, isAddressOfOperand, Fn);
+    QualType ArgType = GetTypeOfFunction(S.Context, R, Fn);
+    if (ArgType.isNull()) continue;
 
     //   - If the argument is an overload set (not containing function
     //     templates), trial argument deduction is attempted using each

Modified: cfe/trunk/test/SemaCXX/member-pointer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-pointer.cpp?rev=112258&r1=112257&r2=112258&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/member-pointer.cpp (original)
+++ cfe/trunk/test/SemaCXX/member-pointer.cpp Fri Aug 27 04:08:28 2010
@@ -79,7 +79,7 @@
 
   void (HasMembers::*pmf)() = &HasMembers::f;
   void (*pnf)() = &Fake::f;
-  &hm.f; // expected-error {{must explicitly qualify}} expected-warning{{result unused}}
+  &hm.f; // expected-error {{cannot create a non-constant pointer to member function}}
 
   void (HasMembers::*pmgv)() = &HasMembers::g;
   void (HasMembers::*pmgi)(int) = &HasMembers::g;
@@ -142,8 +142,8 @@
     void f() {
       void (c::*p)();
       p = &h; // expected-error {{must explicitly qualify}}
-      p = &this->h; // expected-error {{must explicitly qualify}}
-      p = &(*this).h; // expected-error {{must explicitly qualify}}
+      p = &this->h; // expected-error {{cannot create a non-constant pointer to member function}}
+      p = &(*this).h; // expected-error {{cannot create a non-constant pointer to member function}}
     }
   };
 }
@@ -174,3 +174,64 @@
   void m()
   { (void)(Condition) &base::Continuous::cond; }
 }
+
+namespace rdar8358512 {
+  // We can't call this with an overload set because we're not allowed
+  // to look into overload sets unless the parameter has some kind of
+  // function type.
+  template <class F> void bind(F f); // expected-note 6 {{candidate template ignored}}
+  template <class F, class T> void bindmem(F (T::*f)()); // expected-note 4 {{candidate template ignored}}
+  template <class F> void bindfn(F (*f)()); // expected-note 4 {{candidate template ignored}}
+
+  struct A {
+    void member();
+
+    void nonstat();
+    void nonstat(int);
+
+    void mixed();
+    static void mixed(int);
+
+    static void stat();
+    static void stat(int);
+    
+    template <typename T> struct Test0 {
+      void test() {
+        bind(&nonstat); // expected-error {{no matching function for call}}
+        bind(&A::nonstat); // expected-error {{no matching function for call}}
+
+        bind(&mixed); // expected-error {{no matching function for call}}
+        bind(&A::mixed); // expected-error {{no matching function for call}}
+
+        bind(&stat); // expected-error {{no matching function for call}}
+        bind(&A::stat); // expected-error {{no matching function for call}}
+      }
+    };
+
+    template <typename T> struct Test1 {
+      void test() {
+        bindmem(&nonstat); // expected-error {{no matching function for call}}
+        bindmem(&A::nonstat);
+
+        bindmem(&mixed); // expected-error {{no matching function for call}}
+        bindmem(&A::mixed);
+
+        bindmem(&stat); // expected-error {{no matching function for call}}
+        bindmem(&A::stat); // expected-error {{no matching function for call}}
+      }
+    };
+
+    template <typename T> struct Test2 {
+      void test() {
+        bindfn(&nonstat); // expected-error {{no matching function for call}}
+        bindfn(&A::nonstat); // expected-error {{no matching function for call}}
+
+        bindfn(&mixed); // expected-error {{no matching function for call}}
+        bindfn(&A::mixed); // expected-error {{no matching function for call}}
+
+        bindfn(&stat);
+        bindfn(&A::stat);
+      }
+    };
+  };
+}





More information about the cfe-commits mailing list