Basic support for taking the address of an overloaded function

llvm-svn: 59000
This commit is contained in:
Douglas Gregor 2008-11-10 20:40:00 +00:00
parent 74eefb5722
commit cd695e500d
9 changed files with 203 additions and 14 deletions

View File

@ -198,10 +198,11 @@ public:
NamedDecl *getDecl() { return D; } NamedDecl *getDecl() { return D; }
const NamedDecl *getDecl() const { return D; } const NamedDecl *getDecl() const { return D; }
void setDecl(NamedDecl *NewD) { D = NewD; }
SourceLocation getLocation() const { return Loc; } SourceLocation getLocation() const { return Loc; }
virtual SourceRange getSourceRange() const { return SourceRange(Loc); } virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
static bool classof(const Stmt *T) { static bool classof(const Stmt *T) {
return T->getStmtClass() == DeclRefExprClass || return T->getStmtClass() == DeclRefExprClass ||
T->getStmtClass() == CXXConditionDeclExprClass; T->getStmtClass() == CXXConditionDeclExprClass;

View File

@ -356,6 +356,7 @@ public:
bool isObjCInterfaceType() const; // NSString or NSString<foo> bool isObjCInterfaceType() const; // NSString or NSString<foo>
bool isObjCQualifiedInterfaceType() const; // NSString<foo> bool isObjCQualifiedInterfaceType() const; // NSString<foo>
bool isObjCQualifiedIdType() const; // id<foo> bool isObjCQualifiedIdType() const; // id<foo>
bool isOverloadType() const; // C++ overloaded function
// Type Checking Functions: Check to see if this type is structurally the // Type Checking Functions: Check to see if this type is structurally the
// specified type, ignoring typedefs and qualifiers, and return a pointer to // 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 { inline bool Type::isObjCQualifiedIdType() const {
return isa<ObjCQualifiedIdType>(CanonicalType.getUnqualifiedType()); return isa<ObjCQualifiedIdType>(CanonicalType.getUnqualifiedType());
} }
inline bool Type::isOverloadType() const {
if (const BuiltinType *BT = getAsBuiltinType())
return BT->getKind() == BuiltinType::Overload;
else
return false;
}
} // end namespace clang } // end namespace clang
#endif #endif

View File

@ -438,6 +438,10 @@ public:
void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet, void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
bool OnlyViable); bool OnlyViable);
FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
bool Complain);
void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
/// Helpers for dealing with function parameters /// Helpers for dealing with function parameters
bool CheckParmsForFunctionDef(FunctionDecl *FD); bool CheckParmsForFunctionDef(FunctionDecl *FD);

View File

@ -1529,6 +1529,22 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
QualType T1 = DeclType->getAsReferenceType()->getPointeeType(); QualType T1 = DeclType->getAsReferenceType()->getPointeeType();
QualType T2 = Init->getType(); 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. // Compute some basic properties of the types and the initializer.
bool DerivedToBase = false; bool DerivedToBase = false;
Expr::isLvalueResult InitLvalue = Init->isLvalue(Context); Expr::isLvalueResult InitLvalue = Init->isLvalue(Context);

View File

@ -2511,6 +2511,8 @@ static NamedDecl *getPrimaryDecl(Expr *E) {
/// object cannot be declared with storage class register or be a bit field. /// 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 & /// 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. /// 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) { QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
if (getLangOptions().C99) { if (getLangOptions().C99) {
// Implement C99-only parts of addressof rules. // Implement C99-only parts of addressof rules.
@ -2554,7 +2556,9 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
std::string("register variable"), op->getSourceRange()); std::string("register variable"), op->getSourceRange());
return QualType(); return QualType();
} }
} else } else if (isa<OverloadedFunctionDecl>(dcl))
return Context.OverloadTy;
else
assert(0 && "Unknown/unexpected decl type"); assert(0 && "Unknown/unexpected decl type");
} }

View File

@ -280,7 +280,16 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
break; break;
case ICK_Array_To_Pointer: 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); ImpCastExprToType(From, FromType);
break; break;

View File

@ -426,7 +426,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// converted to an rvalue. // converted to an rvalue.
Expr::isLvalueResult argIsLvalue = From->isLvalue(Context); Expr::isLvalueResult argIsLvalue = From->isLvalue(Context);
if (argIsLvalue == Expr::LV_Valid && if (argIsLvalue == Expr::LV_Valid &&
!FromType->isFunctionType() && !FromType->isArrayType()) { !FromType->isFunctionType() && !FromType->isArrayType() &&
!FromType->isOverloadType()) {
SCS.First = ICK_Lvalue_To_Rvalue; SCS.First = ICK_Lvalue_To_Rvalue;
// If T is a non-class type, the type of the rvalue is the // If T is a non-class type, the type of the rvalue is the
@ -465,8 +466,19 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
// type "pointer to T." The result is a pointer to the // type "pointer to T." The result is a pointer to the
// function. (C++ 4.3p1). // function. (C++ 4.3p1).
FromType = Context.getPointerType(FromType); FromType = Context.getPointerType(FromType);
}
// Address of overloaded function (C++ [over.over]).
else if (FunctionDecl *Fn
= ResolveAddressOfOverloadedFunction(From, ToType, false)) {
SCS.First = ICK_Function_To_Pointer;
// FIXME: Deal with overloaded functions here (C++ 4.3p2). // 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. // We don't require any conversions for the first step.
else { else {
@ -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<UnaryOperator>(OvlExpr)) {
if (UnOp->getOpcode() == UnaryOperator::AddrOf)
OvlExpr = UnOp->getSubExpr()->IgnoreParens();
}
// Try to dig out the overloaded function.
if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(OvlExpr))
Ovl = dyn_cast<OverloadedFunctionDecl>(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<CXXMethodDecl>(*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<ParenExpr>(E)) {
FixOverloadedFunctionReference(PE->getSubExpr(), Fn);
E->setType(PE->getSubExpr()->getType());
} else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(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<DeclRefExpr>(E)) {
assert(isa<OverloadedFunctionDecl>(DR->getDecl()) &&
"Expected overloaded function");
DR->setDecl(Fn);
E->setType(Fn->getType());
} else {
assert(false && "Invalid reference to overloaded function");
}
}
} // end namespace clang } // end namespace clang

View File

@ -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 '<overloaded function type>', 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:}}
}

View File

@ -927,7 +927,16 @@ welcome!</p>
<td class="broken" align="center"></td> <td class="broken" align="center"></td>
<td></td> <td></td>
</tr> </tr>
<tr><td>&nbsp;&nbsp;13.4 [over.over]</td><td></td><td></td><td></td><td></td><td></td></tr> <tr>
<td>&nbsp;&nbsp;13.4 [over.over]</td>
<td class="advanced" align="center"></td>
<td class="medium" align="center"></td>
<td class="basic" align="center"></td>
<td class="broken" align="center"></td>
<td>Error messages need some work. Without templates or using
declarations, we don't have any ambiguities, so the semantic
analysis is incomplete.</td>
</tr>
<tr> <tr>
<td>&nbsp;&nbsp;13.5 [over.oper]</td> <td>&nbsp;&nbsp;13.5 [over.oper]</td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
@ -940,7 +949,7 @@ welcome!</p>
<td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.1 [over.unary]</td> <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.1 [over.unary]</td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="medium" align="center"></td> <td class="basic" align="center"></td>
<td class="broken" align="center"></td> <td class="broken" align="center"></td>
<td></td> <td></td>
</tr> </tr>
@ -948,7 +957,7 @@ welcome!</p>
<td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.2 [over.binary]</td> <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.2 [over.binary]</td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="basic" align="center"></td> <td class="medium" align="center"></td>
<td class="broken" align="center"></td> <td class="broken" align="center"></td>
<td></td> <td></td>
</tr> </tr>
@ -956,7 +965,7 @@ welcome!</p>
<td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.3 [over.ass]</td> <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.3 [over.ass]</td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="medium" align="center"></td> <td class="basic" align="center"></td>
<td class="broken" align="center"></td> <td class="broken" align="center"></td>
<td></td> <td></td>
</tr> </tr>
@ -964,7 +973,7 @@ welcome!</p>
<td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.4 [over.call]</td> <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.4 [over.call]</td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="medium" align="center"></td> <td class="basic" align="center"></td>
<td class="broken" align="center"></td> <td class="broken" align="center"></td>
<td></td> <td></td>
</tr> </tr>
@ -972,7 +981,7 @@ welcome!</p>
<td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.5 [over.sub]</td> <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.5 [over.sub]</td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="medium" align="center"></td> <td class="basic" align="center"></td>
<td class="broken" align="center"></td> <td class="broken" align="center"></td>
<td></td> <td></td>
</tr> </tr>
@ -980,7 +989,7 @@ welcome!</p>
<td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.6 [over.ref]</td> <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.6 [over.ref]</td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="medium" align="center"></td> <td class="basic" align="center"></td>
<td class="broken" align="center"></td> <td class="broken" align="center"></td>
<td></td> <td></td>
</tr> </tr>
@ -988,7 +997,7 @@ welcome!</p>
<td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.7 [over.inc]</td> <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.7 [over.inc]</td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="advanced" align="center"></td> <td class="advanced" align="center"></td>
<td class="medium" align="center"></td> <td class="basic" align="center"></td>
<td class="broken" align="center"></td> <td class="broken" align="center"></td>
<td></td> <td></td>
</tr> </tr>