aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-12-14 21:23:13 +0000
committerDouglas Gregor <dgregor@apple.com>2011-12-14 21:23:13 +0000
commitd3d08533116b4ad5ff5d29c88a0e136687297058 (patch)
tree3a1db6002555c7b75852bedc82448afbd89e5710
parent6af27ec69560f7e4b0dac4a0b4341cd6062f6852 (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.cpp45
-rw-r--r--test/CXX/expr/expr.unary/expr.unary.op/p3.cpp28
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;
+}