]> granicus.if.org Git - clang/commitdiff
When trying to resolve the address of an overloaded expression,
authorJohn McCall <rjmccall@apple.com>
Tue, 24 Aug 2010 22:52:39 +0000 (22:52 +0000)
committerJohn McCall <rjmccall@apple.com>
Tue, 24 Aug 2010 22:52:39 +0000 (22:52 +0000)
only form pointers-to-member if the expression has the appropriate
form.  This avoids assertions later on on invalid code, but also
allows us to properly resolve mixed-staticity overloads.

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaExpr.cpp
lib/Sema/SemaOverload.cpp
test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp

index 2a262980a98adc1f410f0994c652ab83ccdcd949..9db39b019d779b47bfa98569592c4ef82932d4a7 100644 (file)
@@ -1286,6 +1286,8 @@ def err_addr_ovl_ambiguous : Error<
   "address of overloaded function %0 is ambiguous">;
 def err_addr_ovl_not_func_ptrref : Error<
   "address of overloaded function %0 cannot be converted to type %1">;
+def err_addr_ovl_no_qualifier : Error<
+  "can't form member pointer of type %0 without '&' and class name">;
   
 // C++ Template Declarations
 def err_template_param_shadow : Error<
index 6acef58f2c2cdfd49ba5d6ebdec7e0e63a453035..30d294cd75279428eb20db478273f9f5515a31e7 100644 (file)
@@ -1063,10 +1063,10 @@ static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef,
 }
 
 ExprResult Sema::ActOnIdExpression(Scope *S,
-                                               CXXScopeSpec &SS,
-                                               UnqualifiedId &Id,
-                                               bool HasTrailingLParen,
-                                               bool isAddressOfOperand) {
+                                   CXXScopeSpec &SS,
+                                   UnqualifiedId &Id,
+                                   bool HasTrailingLParen,
+                                   bool isAddressOfOperand) {
   assert(!(isAddressOfOperand && HasTrailingLParen) &&
          "cannot be direct & operand and have a trailing lparen");
 
@@ -1223,12 +1223,16 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
   }
 
   // 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.
+  // C++ [class.mfct.non-static]p3:
+  //   When an id-expression that is not part of a class member access
+  //   syntax and not used to form a pointer to member is used in the
+  //   body of a non-static member function of class X, if name lookup
+  //   resolves the name in the id-expression to a non-static non-type
+  //   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.
   if (!R.empty() && (*R.begin())->isCXXClassMember()) {
     bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty());
     if (!isAbstractMemberPointer)
index fd22ad93a0944c5ce57980717561504a2e9b817c..65cd183318679f347f6752c131d0fe3fe48e54dd 100644 (file)
@@ -6216,13 +6216,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
   // C++ [over.over]p1:
   //   [...] The overloaded function name can be preceded by the &
   //   operator.
-  OverloadExpr *OvlExpr = OverloadExpr::find(From).getPointer();
-  TemplateArgumentListInfo ETABuffer, *ExplicitTemplateArgs = 0;
-  if (OvlExpr->hasExplicitTemplateArgs()) {
-    OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer);
-    ExplicitTemplateArgs = &ETABuffer;
-  }
-  
+  llvm::PointerIntPair<OverloadExpr*,1> Ovl = OverloadExpr::find(From);
+  OverloadExpr *OvlExpr = Ovl.getPointer();
+
   // We expect a pointer or reference to function, or a function pointer.
   FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType();
   if (!FunctionType->isFunctionType()) {
@@ -6233,6 +6229,30 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
     return 0;
   }
 
+  // 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:
+  //   C++ [expr.unary.op]p4:
+  //     A pointer to member is only formed when an explicit & is used
+  //     and its operand is a qualified-id not enclosed in
+  //     parentheses.
+  // We don't diagnose the parentheses here, though.  Should we?
+  if (IsMember && !(Ovl.getInt() && OvlExpr->getQualifier())) {
+    if (!Complain) return 0;
+
+    // TODO: Should we condition this on whether any functions might
+    // have matched, or is it more appropriate to do that in callers?
+    // TODO: a fixit wouldn't hurt.
+    Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier)
+      << ToType << OvlExpr->getSourceRange();
+    return 0;
+  }
+
+  TemplateArgumentListInfo ETABuffer, *ExplicitTemplateArgs = 0;
+  if (OvlExpr->hasExplicitTemplateArgs()) {
+    OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer);
+    ExplicitTemplateArgs = &ETABuffer;
+  }
+
   assert(From->getType() == Context.OverloadTy);
 
   // Look through all of the overloaded functions, searching for one
index c81e4ef1b1b873d439265e2383916c63807d06d8..7e09bc8aef2c2e0b07b5fd4f94a206e3c05e532e 100644 (file)
@@ -91,3 +91,28 @@ namespace test2 {
     a.test3(); // expected-note {{in instantiation}}
   }
 }
+
+namespace test3 {
+  struct A {
+    void foo(void (A::*)(int)); // expected-note {{passing argument to parameter here}}
+    template<typename T> void g(T);
+
+    void test() {
+      foo(&g<int>); // expected-error {{cannot initialize a parameter}}
+    }
+  };
+}
+
+// This should succeed.
+namespace test4 {
+  struct A {
+    static void f(void (A::*)());
+    static void f(void (*)(int));
+    void g();
+    static void g(int);
+
+    void test() {
+      f(&g);
+    }
+  };
+}