aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/AST/Expr.cpp1
-rw-r--r--lib/Sema/SemaExprCXX.cpp34
-rw-r--r--lib/Sema/SemaOverload.cpp62
-rw-r--r--test/CodeGenCXX/address-of-fntemplate.cpp14
4 files changed, 60 insertions, 51 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 308f6b4dc0..82526119e2 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1345,6 +1345,7 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
case PredefinedExprClass:
return LV_Valid;
case UnresolvedLookupExprClass:
+ case UnresolvedMemberExprClass:
return LV_Valid;
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx);
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 7c324235ca..60ced725e9 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1660,6 +1660,21 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
return false;
}
+ // Resolve overloaded function references.
+ if (Context.hasSameType(FromType, Context.OverloadTy)) {
+ DeclAccessPair Found;
+ FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType,
+ true, Found);
+ if (!Fn)
+ return true;
+
+ if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
+ return true;
+
+ From = FixOverloadedFunctionReference(From, Found, Fn);
+ FromType = From->getType();
+ }
+
// Perform the first implicit conversion.
switch (SCS.First) {
case ICK_Identity:
@@ -1673,25 +1688,6 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
break;
case ICK_Function_To_Pointer:
- if (Context.getCanonicalType(FromType) == Context.OverloadTy) {
- DeclAccessPair Found;
- FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType,
- true, Found);
- if (!Fn)
- return true;
-
- if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
- return true;
-
- From = FixOverloadedFunctionReference(From, Found, Fn);
- FromType = From->getType();
-
- // If there's already an address-of operator in the expression, we have
- // the right type already, and the code below would just introduce an
- // invalid additional pointer level.
- if (FromType->isPointerType() || FromType->isMemberFunctionPointerType())
- break;
- }
FromType = Context.getPointerType(FromType);
ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay);
break;
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 06b5fcb318..2a2521a32c 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -622,8 +622,36 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// array-to-pointer conversion, or function-to-pointer conversion
// (C++ 4p1).
- DeclAccessPair AccessPair;
-
+ if (FromType == Context.OverloadTy) {
+ DeclAccessPair AccessPair;
+ if (FunctionDecl *Fn
+ = ResolveAddressOfOverloadedFunction(From, ToType, false,
+ AccessPair)) {
+ // We were able to resolve the address of the overloaded function,
+ // so we can convert to the type of that function.
+ FromType = Fn->getType();
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) {
+ if (!Method->isStatic()) {
+ Type *ClassType
+ = Context.getTypeDeclType(Method->getParent()).getTypePtr();
+ FromType = 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() == UnaryOperator::AddrOf)
+ FromType = Context.getPointerType(FromType);
+
+ // Check that we've computed the proper type after overload resolution.
+ assert(Context.hasSameType(FromType,
+ FixOverloadedFunctionReference(From, AccessPair, Fn)->getType()));
+ } else {
+ return false;
+ }
+ }
// Lvalue-to-rvalue conversion (C++ 4.1):
// An lvalue (3.10) of a non-function, non-array type T can be
// converted to an rvalue.
@@ -668,36 +696,6 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// type "pointer to T." The result is a pointer to the
// function. (C++ 4.3p1).
FromType = Context.getPointerType(FromType);
- } else if (From->getType() == Context.OverloadTy) {
- if (FunctionDecl *Fn
- = ResolveAddressOfOverloadedFunction(From, ToType, false,
- AccessPair)) {
- // Address of overloaded function (C++ [over.over]).
- SCS.First = ICK_Function_To_Pointer;
-
- // We were able to resolve the address of the overloaded function,
- // so we can convert to the type of that function.
- FromType = Fn->getType();
- if (ToType->isLValueReferenceType())
- FromType = Context.getLValueReferenceType(FromType);
- else if (ToType->isRValueReferenceType())
- FromType = Context.getRValueReferenceType(FromType);
- else if (ToType->isMemberPointerType()) {
- // Resolve address only succeeds if both sides are member pointers,
- // but it doesn't have to be the same class. See DR 247.
- // Note that this means that the type of &Derived::fn can be
- // Ret (Base::*)(Args) if the fn overload actually found is from the
- // base class, even if it was brought into the derived class via a
- // using declaration. The standard isn't clear on this issue at all.
- CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
- FromType = Context.getMemberPointerType(FromType,
- Context.getTypeDeclType(M->getParent()).getTypePtr());
- } else {
- FromType = Context.getPointerType(FromType);
- }
- } else {
- return false;
- }
} else {
// We don't require any conversions for the first step.
SCS.First = ICK_Identity;
diff --git a/test/CodeGenCXX/address-of-fntemplate.cpp b/test/CodeGenCXX/address-of-fntemplate.cpp
index c5fa89d86d..162c6e5754 100644
--- a/test/CodeGenCXX/address-of-fntemplate.cpp
+++ b/test/CodeGenCXX/address-of-fntemplate.cpp
@@ -11,3 +11,17 @@ void test() {
}
// CHECK: define linkonce_odr void @_Z1fIiEvT_
// CHECK: define linkonce_odr void @_Z1fIiEvv
+
+namespace PR6973 {
+ template<typename T>
+ struct X {
+ void f(const T&);
+ };
+
+ template<typename T>
+ int g();
+
+ void h(X<int (*)()> xf) {
+ xf.f(&g<int>);
+ }
+}