diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-12-14 21:23:13 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-12-14 21:23:13 +0000 |
commit | d3d08533116b4ad5ff5d29c88a0e136687297058 (patch) | |
tree | 3a1db6002555c7b75852bedc82448afbd89e5710 | |
parent | 6af27ec69560f7e4b0dac4a0b4341cd6062f6852 (diff) |
Don't consider an overloaded operator& when the expression is actually
going to be a pointer-to-member constant. Fixes <rdar://problem/10544564>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146587 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 45 | ||||
-rw-r--r-- | test/CXX/expr/expr.unary/expr.unary.op/p3.cpp | 28 |
2 files changed, 72 insertions, 1 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index d0aa0a6e7c..d9626369d9 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 0000000000..2dd6b23fa0 --- /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; +} |