diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index d0aa0a6e7c3a3c06bb822a76bd7eb011bba18b19..d9626369d9d440017d5fd4483cbde34c758bec6b 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8257,6 +8257,48 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, VK, OK, OpLoc)); } +/// \brief Determine whether the given expression is a qualified member +/// access expression, of a form that could be turned into a pointer to member +/// with the address-of operator. +static bool isQualifiedMemberAccess(Expr *E) { + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + if (!DRE->getQualifier()) + return false; + + ValueDecl *VD = DRE->getDecl(); + if (!VD->isCXXClassMember()) + return false; + + if (isa<FieldDecl>(VD) || isa<IndirectFieldDecl>(VD)) + return true; + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(VD)) + return Method->isInstance(); + + return false; + } + + if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { + if (!ULE->getQualifier()) + return false; + + for (UnresolvedLookupExpr::decls_iterator D = ULE->decls_begin(), + DEnd = ULE->decls_end(); + D != DEnd; ++D) { + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*D)) { + if (Method->isInstance()) + return true; + } else { + // Overload set does not contain methods. + break; + } + } + + return false; + } + + return false; +} + ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *Input) { // First things first: handle placeholders so that the @@ -8286,7 +8328,8 @@ ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, } if (getLangOptions().CPlusPlus && Input->getType()->isOverloadableType() && - UnaryOperator::getOverloadedOperator(Opc) != OO_None) { + UnaryOperator::getOverloadedOperator(Opc) != OO_None && + !(Opc == UO_AddrOf && isQualifiedMemberAccess(Input))) { // Find all of the overloaded operators visible from this // point. We perform both an operator-name lookup from the local // scope and an argument-dependent lookup based on the types of diff --git a/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp b/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2dd6b23fa0249630f97031259388fd2fa0ad5245 --- /dev/null +++ b/test/CXX/expr/expr.unary/expr.unary.op/p3.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -fsyntax-only %s -verify + +namespace rdar10544564 { + // Check that we don't attempt to use an overloaded operator& when + // naming a pointer-to-member. + struct X { + void** operator & (); + }; + + struct Y + { + public: + X member; + X memfunc1(); + X memfunc2(); + X memfunc2(int); + + void test() { + X Y::*data_mem_ptr = &Y::member; + X (Y::*func_mem_ptr1)() = &Y::memfunc1; + X (Y::*func_mem_ptr2)() = &Y::memfunc2; + } + }; + + X Y::*data_mem_ptr = &Y::member; + X (Y::*func_mem_ptr1)() = &Y::memfunc1; + X (Y::*func_mem_ptr2)() = &Y::memfunc2; +}