diff options
| author | Douglas Gregor <dgregor@apple.com> | 2008-11-10 20:40:00 +0000 |
|---|---|---|
| committer | Douglas Gregor <dgregor@apple.com> | 2008-11-10 20:40:00 +0000 |
| commit | cd695e500de7e628b1feb3425423dec85eb4d5ba (patch) | |
| tree | 15fd5d04bd245b48af239bc199c129001dcd65b6 /clang/lib | |
| parent | 74eefb5722372f49280e452fa680fb3da8aa1ab0 (diff) | |
| download | bcm5719-llvm-cd695e500de7e628b1feb3425423dec85eb4d5ba.tar.gz bcm5719-llvm-cd695e500de7e628b1feb3425423dec85eb4d5ba.zip | |
Basic support for taking the address of an overloaded function
llvm-svn: 59000
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Sema/Sema.h | 4 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 16 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 11 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 115 |
5 files changed, 147 insertions, 5 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index d7518e0aa7b..3b187f2099d 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/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/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 3495880d22f..2f43e5fa9ec 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3bb7c09ce86..a45d6717b79 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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<OverloadedFunctionDecl>(dcl)) + return Context.OverloadTy; + else assert(0 && "Unknown/unexpected decl type"); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 41ee8ddcae4..a6a62a9e377 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/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/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 176701e57d2..b60e55492ba 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/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<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 |

