[cfe-commits] r128456 - in /cfe/trunk: lib/Sema/SemaOverload.cpp test/CXX/over/over.over/p2-resolve-single-template-id.cpp

Chandler Carruth chandlerc at gmail.com
Tue Mar 29 01:08:18 PDT 2011


Author: chandlerc
Date: Tue Mar 29 03:08:18 2011
New Revision: 128456

URL: http://llvm.org/viewvc/llvm-project?rev=128456&view=rev
Log:
Fix a bug in how we were resolving the address of overloaded functions
when the resolution took place due to a single template specialization
being named with an explicit template argument list. In this case, the
"resolution" doesn't take into account the target type at all, and
therefore can take place for functions, static member functions, and
*non-static* member functions. The latter weren't being properly checked
and their proper form enforced in this scenario. We now do so.

The result of this last form slipping through was some confusing logic
in IsStandardConversion handling of these resolved address-of
expressions which eventually exploded in an assert. Simplify this logic
a bit and add some more aggressive asserts to catch improperly formed
expressions getting into this routine.

Finally add systematic testing of member functions, both static and
non-static, in the various forms they can take. One of these is
essentially PR9563, and this commit fixes the crash in that PR. However,
the diagnostics for this are still pretty terrible. We at least are now
accepting the correct constructs and rejecting the invalid ones rather
than accepting invalid or crashing as before.

Modified:
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/test/CXX/over/over.over/p2-resolve-single-template-id.cpp

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=128456&r1=128455&r2=128456&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Mar 29 03:08:18 2011
@@ -1058,27 +1058,33 @@
           // otherwise, only a boolean conversion is standard   
           if (!ToType->isBooleanType()) 
             return false; 
-
-      }
-        
-      if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
-        if (!Method->isStatic()) {
-          const Type *ClassType
-            = S.Context.getTypeDeclType(Method->getParent()).getTypePtr();
-          FromType = S.Context.getMemberPointerType(FromType, ClassType);
-        }
       }
 
-      // If the "from" expression takes the address of the overloaded
-      // function, update the type of the resulting expression accordingly.
-      if (FromType->getAs<FunctionType>())
-        if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(From->IgnoreParens()))
-          if (UnOp->getOpcode() == UO_AddrOf)
-            FromType = S.Context.getPointerType(FromType);
+      // Check if the "from" expression is taking the address of an overloaded
+      // function and recompute the FromType accordingly. Take advantage of the
+      // fact that non-static member functions *must* have such an address-of
+      // expression. 
+      CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn);
+      if (Method && !Method->isStatic()) {
+        assert(isa<UnaryOperator>(From->IgnoreParens()) &&
+               "Non-unary operator on non-static member address");
+        assert(cast<UnaryOperator>(From->IgnoreParens())->getOpcode()
+               == UO_AddrOf &&
+               "Non-address-of operator on non-static member address");
+        const Type *ClassType
+          = S.Context.getTypeDeclType(Method->getParent()).getTypePtr();
+        FromType = S.Context.getMemberPointerType(FromType, ClassType);
+      } else if (UnaryOperator *UnOp
+                 = dyn_cast<UnaryOperator>(From->IgnoreParens())) {
+        assert(UnOp->getOpcode() == UO_AddrOf &&
+               "Non-address-of operator for overloaded function expression");
+        FromType = S.Context.getPointerType(FromType);
+      }
 
       // Check that we've computed the proper type after overload resolution.
-      assert(S.Context.hasSameType(FromType,
-            S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType()));
+      assert(S.Context.hasSameType(
+        FromType,
+        S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType()));
     } else {
       return false;
     }
@@ -7174,6 +7180,21 @@
         DeclAccessPair dap;
         if( FunctionDecl* Fn = S.ResolveSingleFunctionTemplateSpecialization(
                                             OvlExpr, false, &dap) ) {
+
+          if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
+            if (!Method->isStatic()) {
+              // If the target type is a non-function type and the function
+              // found is a non-static member function, pretend as if that was
+              // the target, it's the only possible type to end up with.
+              TargetTypeIsNonStaticMemberFunction = true;
+
+              // And skip adding the function if its not in the proper form.
+              // We'll diagnose this due to an empty set of functions.
+              if (!OvlExprInfo.HasFormOfMemberPointer)
+                return;
+            }
+          }
+
           Matches.push_back(std::make_pair(dap,Fn));
         }
       }

Modified: cfe/trunk/test/CXX/over/over.over/p2-resolve-single-template-id.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/over/over.over/p2-resolve-single-template-id.cpp?rev=128456&r1=128455&r2=128456&view=diff
==============================================================================
--- cfe/trunk/test/CXX/over/over.over/p2-resolve-single-template-id.cpp (original)
+++ cfe/trunk/test/CXX/over/over.over/p2-resolve-single-template-id.cpp Tue Mar 29 03:08:18 2011
@@ -123,4 +123,68 @@
 
 }
 
+namespace member_pointers {
+  struct S {
+    template <typename T> bool f(T) { return false; }
+    template <typename T> static bool g(T) { return false; }
 
+    template <typename T> bool h(T) { return false; }
+    template <int N> static bool h(int) { return false; }
+  };
+
+  void test(S s) {
+    if (S::f<char>) return; // expected-error {{call to non-static member function without an object argument}}
+    if (S::f<int>) return; // expected-error {{call to non-static member function without an object argument}}
+    if (&S::f<char>) return;
+    if (&S::f<int>) return;
+    if (s.f<char>) return; // expected-error {{contextually convertible}}
+    if (s.f<int>) return; // expected-error {{contextually convertible}}
+    if (&s.f<char>) return; // expected-error {{contextually convertible}}
+    if (&s.f<int>) return; // expected-error {{contextually convertible}}
+
+    if (S::g<char>) return;
+    if (S::g<int>) return;
+    if (&S::g<char>) return;
+    if (&S::g<int>) return;
+    if (s.g<char>) return;
+    if (s.g<int>) return;
+    if (&s.g<char>) return;
+    if (&s.g<int>) return;
+
+    if (S::h<42>) return;
+    if (S::h<int>) return; // expected-error {{contextually convertible}}
+    if (&S::h<42>) return;
+    if (&S::h<int>) return;
+    if (s.h<42>) return;
+    if (s.h<int>) return; // expected-error {{contextually convertible}}
+    if (&s.h<42>) return;
+    if (&s.h<int>) return; // expected-error {{contextually convertible}}
+
+    { bool b = S::f<char>; } // expected-error {{call to non-static member function without an object argument}}
+    { bool b = S::f<int>; } // expected-error {{call to non-static member function without an object argument}}
+    { bool b = &S::f<char>; }
+    { bool b = &S::f<int>; }
+    { bool b = s.f<char>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+    { bool b = s.f<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+    { bool b = &s.f<char>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+    { bool b = &s.f<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+
+    { bool b = S::g<char>; }
+    { bool b = S::g<int>; }
+    { bool b = &S::g<char>; }
+    { bool b = &S::g<int>; }
+    { bool b = s.g<char>; }
+    { bool b = s.g<int>; }
+    { bool b = &s.g<char>; }
+    { bool b = &s.g<int>; }
+
+    { bool b = S::h<42>; }
+    { bool b = S::h<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+    { bool b = &S::h<42>; }
+    { bool b = &S::h<int>; }
+    { bool b = s.h<42>; }
+    { bool b = s.h<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+    { bool b = &s.h<42>; }
+    { bool b = &s.h<int>; } // expected-error {{can't form member pointer of type 'bool' without '&' and class name}}
+  }
+}





More information about the cfe-commits mailing list