diff options
author | John McCall <rjmccall@apple.com> | 2010-08-24 22:52:39 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-08-24 22:52:39 +0000 |
commit | fb97e75e627599aaa7a613778134e290f9de663b (patch) | |
tree | 18855c1b8c3f75781ed9dd333e7754ae1931766d | |
parent | 4153a060f4cd03e9db1349328a158e9d898a2610 (diff) |
When trying to resolve the address of an overloaded expression,
only form pointers-to-member if the expression has the appropriate
form. This avoids assertions later on on invalid code, but also
allows us to properly resolve mixed-staticity overloads.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111987 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 24 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 34 | ||||
-rw-r--r-- | test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp | 25 |
4 files changed, 68 insertions, 17 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 2a262980a9..9db39b019d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1286,6 +1286,8 @@ def err_addr_ovl_ambiguous : Error< "address of overloaded function %0 is ambiguous">; def err_addr_ovl_not_func_ptrref : Error< "address of overloaded function %0 cannot be converted to type %1">; +def err_addr_ovl_no_qualifier : Error< + "can't form member pointer of type %0 without '&' and class name">; // C++ Template Declarations def err_template_param_shadow : Error< diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 6acef58f2c..30d294cd75 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1063,10 +1063,10 @@ static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef, } ExprResult Sema::ActOnIdExpression(Scope *S, - CXXScopeSpec &SS, - UnqualifiedId &Id, - bool HasTrailingLParen, - bool isAddressOfOperand) { + CXXScopeSpec &SS, + UnqualifiedId &Id, + bool HasTrailingLParen, + bool isAddressOfOperand) { assert(!(isAddressOfOperand && HasTrailingLParen) && "cannot be direct & operand and have a trailing lparen"); @@ -1223,12 +1223,16 @@ ExprResult Sema::ActOnIdExpression(Scope *S, } // Check whether this might be a C++ implicit instance member access. - // C++ [expr.prim.general]p6: - // Within the definition of a non-static member function, an - // identifier that names a non-static member is transformed to a - // class member access expression. - // But note that &SomeClass::foo is grammatically distinct, even - // though we don't parse it that way. + // C++ [class.mfct.non-static]p3: + // When an id-expression that is not part of a class member access + // syntax and not used to form a pointer to member is used in the + // body of a non-static member function of class X, if name lookup + // resolves the name in the id-expression to a non-static non-type + // member of some class C, the id-expression is transformed into a + // class member access expression using (*this) as the + // postfix-expression to the left of the . operator. + // So if we found a class member with an expression of form other + // than &A::foo, we have to try to build an implicit member expr. if (!R.empty() && (*R.begin())->isCXXClassMember()) { bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty()); if (!isAbstractMemberPointer) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index fd22ad93a0..65cd183318 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -6216,13 +6216,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // C++ [over.over]p1: // [...] The overloaded function name can be preceded by the & // operator. - OverloadExpr *OvlExpr = OverloadExpr::find(From).getPointer(); - TemplateArgumentListInfo ETABuffer, *ExplicitTemplateArgs = 0; - if (OvlExpr->hasExplicitTemplateArgs()) { - OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer); - ExplicitTemplateArgs = &ETABuffer; - } - + llvm::PointerIntPair<OverloadExpr*,1> Ovl = OverloadExpr::find(From); + OverloadExpr *OvlExpr = Ovl.getPointer(); + // We expect a pointer or reference to function, or a function pointer. FunctionType = Context.getCanonicalType(FunctionType).getUnqualifiedType(); if (!FunctionType->isFunctionType()) { @@ -6233,6 +6229,30 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, return 0; } + // If the overload expression doesn't have the form of a pointer to + // member, don't try to convert it to a pointer-to-member type: + // C++ [expr.unary.op]p4: + // A pointer to member is only formed when an explicit & is used + // and its operand is a qualified-id not enclosed in + // parentheses. + // We don't diagnose the parentheses here, though. Should we? + if (IsMember && !(Ovl.getInt() && OvlExpr->getQualifier())) { + if (!Complain) return 0; + + // TODO: Should we condition this on whether any functions might + // have matched, or is it more appropriate to do that in callers? + // TODO: a fixit wouldn't hurt. + Diag(OvlExpr->getNameLoc(), diag::err_addr_ovl_no_qualifier) + << ToType << OvlExpr->getSourceRange(); + return 0; + } + + TemplateArgumentListInfo ETABuffer, *ExplicitTemplateArgs = 0; + if (OvlExpr->hasExplicitTemplateArgs()) { + OvlExpr->getExplicitTemplateArgs().copyInto(ETABuffer); + ExplicitTemplateArgs = &ETABuffer; + } + assert(From->getType() == Context.OverloadTy); // Look through all of the overloaded functions, searching for one diff --git a/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp b/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp index c81e4ef1b1..7e09bc8aef 100644 --- a/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp +++ b/test/CXX/class/class.mfct/class.mfct.non-static/p3.cpp @@ -91,3 +91,28 @@ namespace test2 { a.test3(); // expected-note {{in instantiation}} } } + +namespace test3 { + struct A { + void foo(void (A::*)(int)); // expected-note {{passing argument to parameter here}} + template<typename T> void g(T); + + void test() { + foo(&g<int>); // expected-error {{cannot initialize a parameter}} + } + }; +} + +// This should succeed. +namespace test4 { + struct A { + static void f(void (A::*)()); + static void f(void (*)(int)); + void g(); + static void g(int); + + void test() { + f(&g); + } + }; +} |