diff options
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 55 | ||||
-rw-r--r-- | test/CXX/over/over.over/p2-resolve-single-template-id.cpp | 66 |
2 files changed, 103 insertions, 18 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 6fa78a9a46..8125ce1086 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1058,27 +1058,33 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // 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 @@ public: 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)); } } diff --git a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp index 64871edcbc..f4a5e8f633 100644 --- a/test/CXX/over/over.over/p2-resolve-single-template-id.cpp +++ b/test/CXX/over/over.over/p2-resolve-single-template-id.cpp @@ -123,4 +123,68 @@ int main() } - +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}} + } +} |