From: Douglas Gregor
Date: Mon, 10 Nov 2008 20:40:00 +0000 (+0000)
Subject: Basic support for taking the address of an overloaded function
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=904eed3f6148758d39a2d3c88f3133274460d645;p=clang
Basic support for taking the address of an overloaded function
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59000 91177308-0d34-0410-b5e6-96231b3b80d8
---
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 2c25fcd123..6023c6803d 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -198,10 +198,11 @@ public:
NamedDecl *getDecl() { return D; }
const NamedDecl *getDecl() const { return D; }
+ void setDecl(NamedDecl *NewD) { D = NewD; }
+
SourceLocation getLocation() const { return Loc; }
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
-
static bool classof(const Stmt *T) {
return T->getStmtClass() == DeclRefExprClass ||
T->getStmtClass() == CXXConditionDeclExprClass;
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 7915dd056f..176d67a00e 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -356,6 +356,7 @@ public:
bool isObjCInterfaceType() const; // NSString or NSString
bool isObjCQualifiedInterfaceType() const; // NSString
bool isObjCQualifiedIdType() const; // id
+ bool isOverloadType() const; // C++ overloaded function
// Type Checking Functions: Check to see if this type is structurally the
// specified type, ignoring typedefs and qualifiers, and return a pointer to
@@ -1478,6 +1479,13 @@ inline bool Type::isObjCQualifiedInterfaceType() const {
inline bool Type::isObjCQualifiedIdType() const {
return isa(CanonicalType.getUnqualifiedType());
}
+inline bool Type::isOverloadType() const {
+ if (const BuiltinType *BT = getAsBuiltinType())
+ return BT->getKind() == BuiltinType::Overload;
+ else
+ return false;
+}
+
} // end namespace clang
#endif
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index d7518e0aa7..3b187f2099 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -438,6 +438,10 @@ public:
void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
bool OnlyViable);
+ FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
+ bool Complain);
+ void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
+
/// Helpers for dealing with function parameters
bool CheckParmsForFunctionDef(FunctionDecl *FD);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 3495880d22..2f43e5fa9e 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1529,6 +1529,22 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
QualType T1 = DeclType->getAsReferenceType()->getPointeeType();
QualType T2 = Init->getType();
+ // If the initializer is the address of an overloaded function, try
+ // to resolve the overloaded function. If all goes well, T2 is the
+ // type of the resulting function.
+ if (T2->isOverloadType()) {
+ FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType,
+ ICS != 0);
+ if (Fn) {
+ // Since we're performing this reference-initialization for
+ // real, update the initializer with the resulting function.
+ if (!ICS)
+ FixOverloadedFunctionReference(Init, Fn);
+
+ T2 = Fn->getType();
+ }
+ }
+
// Compute some basic properties of the types and the initializer.
bool DerivedToBase = false;
Expr::isLvalueResult InitLvalue = Init->isLvalue(Context);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 3bb7c09ce8..a45d6717b7 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -2511,6 +2511,8 @@ static NamedDecl *getPrimaryDecl(Expr *E) {
/// object cannot be declared with storage class register or be a bit field.
/// Note: The usual conversions are *not* applied to the operand of the &
/// operator (C99 6.3.2.1p[2-4]), and its result is never an lvalue.
+/// In C++, the operand might be an overloaded function name, in which case
+/// we allow the '&' but retain the overloaded-function type.
QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
if (getLangOptions().C99) {
// Implement C99-only parts of addressof rules.
@@ -2554,7 +2556,9 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
std::string("register variable"), op->getSourceRange());
return QualType();
}
- } else
+ } else if (isa(dcl))
+ return Context.OverloadTy;
+ else
assert(0 && "Unknown/unexpected decl type");
}
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 41ee8ddcae..a6a62a9e37 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -280,7 +280,16 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
break;
case ICK_Array_To_Pointer:
- FromType = Context.getArrayDecayedType(FromType);
+ if (FromType->isOverloadType()) {
+ FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true);
+ if (!Fn)
+ return true;
+
+ FixOverloadedFunctionReference(From, Fn);
+ FromType = From->getType();
+ } else {
+ FromType = Context.getArrayDecayedType(FromType);
+ }
ImpCastExprToType(From, FromType);
break;
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 176701e57d..b60e55492b 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -426,7 +426,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// converted to an rvalue.
Expr::isLvalueResult argIsLvalue = From->isLvalue(Context);
if (argIsLvalue == Expr::LV_Valid &&
- !FromType->isFunctionType() && !FromType->isArrayType()) {
+ !FromType->isFunctionType() && !FromType->isArrayType() &&
+ !FromType->isOverloadType()) {
SCS.First = ICK_Lvalue_To_Rvalue;
// If T is a non-class type, the type of the rvalue is the
@@ -465,9 +466,20 @@ 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);
-
- // FIXME: Deal with overloaded functions here (C++ 4.3p2).
}
+ // Address of overloaded function (C++ [over.over]).
+ else if (FunctionDecl *Fn
+ = ResolveAddressOfOverloadedFunction(From, ToType, false)) {
+ 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->isReferenceType())
+ FromType = Context.getReferenceType(FromType);
+ else
+ FromType = Context.getPointerType(FromType);
+ }
// We don't require any conversions for the first step.
else {
SCS.First = ICK_Identity;
@@ -1681,4 +1693,101 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
}
}
+/// ResolveAddressOfOverloadedFunction - Try to resolve the address of
+/// an overloaded function (C++ [over.over]), where @p From is an
+/// expression with overloaded function type and @p ToType is the type
+/// we're trying to resolve to. For example:
+///
+/// @code
+/// int f(double);
+/// int f(int);
+///
+/// int (*pfd)(double) = f; // selects f(double)
+/// @endcode
+///
+/// This routine returns the resulting FunctionDecl if it could be
+/// resolved, and NULL otherwise. When @p Complain is true, this
+/// routine will emit diagnostics if there is an error.
+FunctionDecl *
+Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
+ bool Complain) {
+ QualType FunctionType = ToType;
+ if (const PointerLikeType *ToTypePtr = ToType->getAsPointerLikeType())
+ FunctionType = ToTypePtr->getPointeeType();
+
+ // We only look at pointers or references to functions.
+ if (!FunctionType->isFunctionType())
+ return 0;
+
+ // Find the actual overloaded function declaration.
+ OverloadedFunctionDecl *Ovl = 0;
+
+ // C++ [over.over]p1:
+ // [...] [Note: any redundant set of parentheses surrounding the
+ // overloaded function name is ignored (5.1). ]
+ Expr *OvlExpr = From->IgnoreParens();
+
+ // C++ [over.over]p1:
+ // [...] The overloaded function name can be preceded by the &
+ // operator.
+ if (UnaryOperator *UnOp = dyn_cast(OvlExpr)) {
+ if (UnOp->getOpcode() == UnaryOperator::AddrOf)
+ OvlExpr = UnOp->getSubExpr()->IgnoreParens();
+ }
+
+ // Try to dig out the overloaded function.
+ if (DeclRefExpr *DR = dyn_cast(OvlExpr))
+ Ovl = dyn_cast(DR->getDecl());
+
+ // If there's no overloaded function declaration, we're done.
+ if (!Ovl)
+ return 0;
+
+ // Look through all of the overloaded functions, searching for one
+ // whose type matches exactly.
+ // FIXME: When templates or using declarations come along, we'll actually
+ // have to deal with duplicates, partial ordering, etc. For now, we
+ // can just do a simple search.
+ FunctionType = Context.getCanonicalType(FunctionType.getUnqualifiedType());
+ for (OverloadedFunctionDecl::function_iterator Fun = Ovl->function_begin();
+ Fun != Ovl->function_end(); ++Fun) {
+ // C++ [over.over]p3:
+ // Non-member functions and static member functions match
+ // targets of type âpointer-to-functionâor
+ // âreference-to-function.â
+ if (CXXMethodDecl *Method = dyn_cast(*Fun))
+ if (!Method->isStatic())
+ continue;
+
+ if (FunctionType == Context.getCanonicalType((*Fun)->getType()))
+ return *Fun;
+ }
+
+ return 0;
+}
+
+/// FixOverloadedFunctionReference - E is an expression that refers to
+/// a C++ overloaded function (possibly with some parentheses and
+/// perhaps a '&' around it). We have resolved the overloaded function
+/// to the function declaration Fn, so patch up the expression E to
+/// refer (possibly indirectly) to Fn.
+void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
+ if (ParenExpr *PE = dyn_cast(E)) {
+ FixOverloadedFunctionReference(PE->getSubExpr(), Fn);
+ E->setType(PE->getSubExpr()->getType());
+ } else if (UnaryOperator *UnOp = dyn_cast(E)) {
+ assert(UnOp->getOpcode() == UnaryOperator::AddrOf &&
+ "Can only take the address of an overloaded function");
+ FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn);
+ E->setType(Context.getPointerType(E->getType()));
+ } else if (DeclRefExpr *DR = dyn_cast(E)) {
+ assert(isa(DR->getDecl()) &&
+ "Expected overloaded function");
+ DR->setDecl(Fn);
+ E->setType(Fn->getType());
+ } else {
+ assert(false && "Invalid reference to overloaded function");
+ }
+}
+
} // end namespace clang
diff --git a/test/SemaCXX/addr-of-overloaded-function.cpp b/test/SemaCXX/addr-of-overloaded-function.cpp
new file mode 100644
index 0000000000..2184116dd2
--- /dev/null
+++ b/test/SemaCXX/addr-of-overloaded-function.cpp
@@ -0,0 +1,29 @@
+// RUN: clang -fsyntax-only -verify %s
+int f(double);
+int f(int);
+
+int (*pfd)(double) = f; // selects f(double)
+int (*pfd2)(double) = &f; // selects f(double)
+int (*pfd3)(double) = ((&((f)))); // selects f(double)
+int (*pfi)(int) = &f; // selects f(int)
+// FIXME: This error message is not very good. We need to keep better
+// track of what went wrong when the implicit conversion failed to
+// give a better error message here.
+int (*pfe)(...) = &f; // expected-error{{incompatible type initializing '', expected 'int (*)(...)'}}
+int (&rfi)(int) = f; // selects f(int)
+int (&rfd)(double) = f; // selects f(double)
+
+void g(int (*fp)(int)); // expected-note{{note: candidate function}}
+void g(int (*fp)(float));
+void g(int (*fp)(double)); // expected-note{{note: candidate function}}
+
+int g1(int);
+int g1(char);
+
+int g2(int);
+int g2(double);
+
+void g_test() {
+ g(g1);
+ g(g2); // expected-error{{call to 'g' is ambiguous; candidates are:}}
+}
diff --git a/www/cxx_status.html b/www/cxx_status.html
index e98ce87a0b..586cb2652b 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -927,7 +927,16 @@ welcome!
|
|
- 13.4 [over.over] | | | | | |
+
+ 13.4 [over.over] |
+ |
+ |
+ |
+ |
+ Error messages need some work. Without templates or using
+ declarations, we don't have any ambiguities, so the semantic
+ analysis is incomplete. |
+
13.5 [over.oper] |
|
@@ -940,7 +949,7 @@ welcome!
13.5.1 [over.unary] |
|
|
- |
+ |
|
|
@@ -948,7 +957,7 @@ welcome!
13.5.2 [over.binary] |
|
|
- |
+ |
|
|
@@ -956,7 +965,7 @@ welcome!
13.5.3 [over.ass] |
|
|
- |
+ |
|
|
@@ -964,7 +973,7 @@ welcome!
13.5.4 [over.call] |
|
|
- |
+ |
|
|
@@ -972,7 +981,7 @@ welcome!
13.5.5 [over.sub] |
|
|
- |
+ |
|
|
@@ -980,7 +989,7 @@ welcome!
13.5.6 [over.ref] |
|
|
- |
+ |
|
|
@@ -988,7 +997,7 @@ welcome!
13.5.7 [over.inc] |
|
|
- |
+ |
|
|