forked from OSchip/llvm-project
Basic support for taking the address of an overloaded function
llvm-svn: 59000
This commit is contained in:
parent
74eefb5722
commit
cd695e500d
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:}}
|
||||||
|
}
|
|
@ -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> 13.4 [over.over]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
<tr>
|
||||||
|
<td> 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> 13.5 [over.oper]</td>
|
<td> 13.5 [over.oper]</td>
|
||||||
<td class="advanced" align="center"></td>
|
<td class="advanced" align="center"></td>
|
||||||
|
@ -940,7 +949,7 @@ welcome!</p>
|
||||||
<td> 13.5.1 [over.unary]</td>
|
<td> 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> 13.5.2 [over.binary]</td>
|
<td> 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> 13.5.3 [over.ass]</td>
|
<td> 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> 13.5.4 [over.call]</td>
|
<td> 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> 13.5.5 [over.sub]</td>
|
<td> 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> 13.5.6 [over.ref]</td>
|
<td> 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> 13.5.7 [over.inc]</td>
|
<td> 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>
|
||||||
|
|
Loading…
Reference in New Issue