]> granicus.if.org Git - clang/commitdiff
Basic support for taking the address of an overloaded function
authorDouglas Gregor <dgregor@apple.com>
Mon, 10 Nov 2008 20:40:00 +0000 (20:40 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 10 Nov 2008 20:40:00 +0000 (20:40 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59000 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Expr.h
include/clang/AST/Type.h
lib/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaOverload.cpp
test/SemaCXX/addr-of-overloaded-function.cpp [new file with mode: 0644]
www/cxx_status.html

index 2c25fcd123c60f6078b16524e41147c576ba6ed4..6023c6803d01237713a34a139d90aacae5d98200 100644 (file)
@@ -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; 
index 7915dd056f77713844b9304a1ea82963dec60ebc..176d67a00eba0c20a8a36ba31d50d8df37a6f2b3 100644 (file)
@@ -356,6 +356,7 @@ public:
   bool isObjCInterfaceType() const;             // NSString or NSString<foo>
   bool isObjCQualifiedInterfaceType() const;    // NSString<foo>
   bool isObjCQualifiedIdType() const;           // id<foo>
+  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<ObjCQualifiedIdType>(CanonicalType.getUnqualifiedType());
 }
+inline bool Type::isOverloadType() const {
+  if (const BuiltinType *BT = getAsBuiltinType())
+    return BT->getKind() == BuiltinType::Overload;
+  else
+    return false;
+}
+
 }  // end namespace clang
 
 #endif
index d7518e0aa7b6c114cf64831e2e2e3733dd7edaa3..3b187f2099d9923d674a5c245c2dcf061465c01a 100644 (file)
@@ -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);
index 3495880d22fcdd3509fb631338cbc8ce3e5c54ab..2f43e5fa9eccf2785019625cd311d021849309f7 100644 (file)
@@ -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);
index 3bb7c09ce8684b89db757e107e5ef6b7ea7c46fa..a45d6717b797a0525ddcbef0eddfa2f156731739 100644 (file)
@@ -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");
   }
   
index 41ee8ddcae430ed7845500eecbcfbe1bc7ff2178..a6a62a9e3775fd90c8bcfb5251d4b5ead3fff0e5 100644 (file)
@@ -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;
 
index 176701e57d2a6d4c42966e6000936030006cbda8..b60e55492ba9e98147c7ad5f42ba9606b7de86c1 100644 (file)
@@ -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
diff --git a/test/SemaCXX/addr-of-overloaded-function.cpp b/test/SemaCXX/addr-of-overloaded-function.cpp
new file mode 100644 (file)
index 0000000..2184116
--- /dev/null
@@ -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:}}
+}
index e98ce87a0bb2eb90b4f14c782658cb93a4957190..586cb2652b9126dadff8f061cd93c9eb28efba72 100644 (file)
@@ -927,7 +927,16 @@ welcome!</p>
   <td class="broken" align="center"></td>  \r
   <td></td>\r
 </tr>\r
-<tr><td>&nbsp;&nbsp;13.4 [over.over]</td><td></td><td></td><td></td><td></td><td></td></tr>\r
+<tr>\r
+  <td>&nbsp;&nbsp;13.4 [over.over]</td>\r
+  <td class="advanced" align="center"></td>  \r
+  <td class="medium" align="center"></td>\r
+  <td class="basic" align="center"></td>\r
+  <td class="broken" align="center"></td>  \r
+  <td>Error messages need some work. Without templates or using\r
+  declarations, we don't have any ambiguities, so the semantic\r
+  analysis is incomplete.</td>\r
+</tr>\r
 <tr>\r
   <td>&nbsp;&nbsp;13.5 [over.oper]</td>\r
   <td class="advanced" align="center"></td>  \r
@@ -940,7 +949,7 @@ welcome!</p>
   <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.1 [over.unary]</td>\r
   <td class="advanced" align="center"></td>  \r
   <td class="advanced" align="center"></td>\r
-  <td class="medium" align="center"></td>\r
+  <td class="basic" align="center"></td>\r
   <td class="broken" align="center"></td>  \r
   <td></td>\r
 </tr>\r
@@ -948,7 +957,7 @@ welcome!</p>
   <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.2 [over.binary]</td>\r
   <td class="advanced" align="center"></td>  \r
   <td class="advanced" align="center"></td>\r
-  <td class="basic" align="center"></td>\r
+  <td class="medium" align="center"></td>\r
   <td class="broken" align="center"></td>  \r
   <td></td>\r
 </tr>\r
@@ -956,7 +965,7 @@ welcome!</p>
   <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.3 [over.ass]</td>\r
   <td class="advanced" align="center"></td>  \r
   <td class="advanced" align="center"></td>\r
-  <td class="medium" align="center"></td>\r
+  <td class="basic" align="center"></td>\r
   <td class="broken" align="center"></td>  \r
   <td></td>\r
 </tr>\r
@@ -964,7 +973,7 @@ welcome!</p>
   <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.4 [over.call]</td>\r
   <td class="advanced" align="center"></td>  \r
   <td class="advanced" align="center"></td>\r
-  <td class="medium" align="center"></td>\r
+  <td class="basic" align="center"></td>\r
   <td class="broken" align="center"></td>  \r
   <td></td>\r
 </tr>\r
@@ -972,7 +981,7 @@ welcome!</p>
   <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.5 [over.sub]</td>\r
   <td class="advanced" align="center"></td>  \r
   <td class="advanced" align="center"></td>\r
-  <td class="medium" align="center"></td>\r
+  <td class="basic" align="center"></td>\r
   <td class="broken" align="center"></td>  \r
   <td></td>\r
 </tr>\r
@@ -980,7 +989,7 @@ welcome!</p>
   <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.6 [over.ref]</td>\r
   <td class="advanced" align="center"></td>  \r
   <td class="advanced" align="center"></td>\r
-  <td class="medium" align="center"></td>\r
+  <td class="basic" align="center"></td>\r
   <td class="broken" align="center"></td>  \r
   <td></td>\r
 </tr>\r
@@ -988,7 +997,7 @@ welcome!</p>
   <td>&nbsp;&nbsp;&nbsp;&nbsp;13.5.7 [over.inc]</td>\r
   <td class="advanced" align="center"></td>  \r
   <td class="advanced" align="center"></td>\r
-  <td class="medium" align="center"></td>\r
+  <td class="basic" align="center"></td>\r
   <td class="broken" align="center"></td>  \r
   <td></td>\r
 </tr>\r