]> granicus.if.org Git - clang/commitdiff
Don't add implicit casts of explicit address-taking of overloaded functions.
authorSebastian Redl <sebastian.redl@getdesigned.at>
Sat, 17 Oct 2009 20:50:27 +0000 (20:50 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Sat, 17 Oct 2009 20:50:27 +0000 (20:50 +0000)
Taking the address of an overloaded function with an explicit address-of operator wrapped the operator in an implicit cast that added yet another pointer level, leaving us with a corrupted AST, which crashed CodeGen in the test case I've added. Fix this by making FixOverloadedFunctionReference return whether there was an address-of operator and not adding the implicit cast in that case.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84362 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/Sema.h
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaOverload.cpp
test/CodeGenCXX/address-of-fntemplate.cpp [new file with mode: 0644]

index 8ebe5ef6fc833aaf6aae99f2f4451bbd116294a6..1cadcecd8818f530d0ebada2a5c5d0a11833f134 100644 (file)
@@ -929,7 +929,7 @@ public:
 
   FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
                                                    bool Complain);
-  void FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
+  bool FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn);
 
   void AddOverloadedCallCandidates(NamedDecl *Callee,
                                    DeclarationName &UnqualifiedName,
index 7fc27a44f7b69fb3417228178f5f239787a648ce..d56c426d00ab7c6e30da6a59499a96343ff5c8c8 100644 (file)
@@ -1222,8 +1222,13 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
       if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin()))
         return true;
 
-      FixOverloadedFunctionReference(From, Fn);
+      bool WasAddrOf = FixOverloadedFunctionReference(From, Fn);
       FromType = From->getType();
+      // If there's already an address-of operator in the expression, we have
+      // the right type already, and the code below would just introduce an
+      // invalid additional pointer level.
+      if (WasAddrOf)
+        break;
     }
     FromType = Context.getPointerType(FromType);
     ImpCastExprToType(From, FromType, CastExpr::CK_FunctionToPointerDecay);
index ecadcd904e28aac28baba9f41adc7ea5aa1655fe..5f874e8dbc95d9c868e2c3ba7052773753640976 100644 (file)
@@ -5300,10 +5300,12 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) {
 /// 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) {
+/// Returns true if the function reference used an explicit address-of operator.
+bool Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
   if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
-    FixOverloadedFunctionReference(PE->getSubExpr(), Fn);
+    bool ret = FixOverloadedFunctionReference(PE->getSubExpr(), Fn);
     E->setType(PE->getSubExpr()->getType());
+    return ret;
   } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) {
     assert(UnOp->getOpcode() == UnaryOperator::AddrOf &&
            "Can only take the address of an overloaded function");
@@ -5322,11 +5324,12 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
           = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
         E->setType(Context.getMemberPointerType(Fn->getType(),
                                                 ClassType.getTypePtr()));
-        return;
+        return true;
       }
     }
     FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn);
     E->setType(Context.getPointerType(UnOp->getSubExpr()->getType()));
+    return true;
   } else if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E)) {
     assert((isa<OverloadedFunctionDecl>(DR->getDecl()) ||
             isa<FunctionTemplateDecl>(DR->getDecl())) &&
@@ -5339,6 +5342,7 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) {
   } else {
     assert(false && "Invalid reference to overloaded function");
   }
+  return false;
 }
 
 } // end namespace clang
diff --git a/test/CodeGenCXX/address-of-fntemplate.cpp b/test/CodeGenCXX/address-of-fntemplate.cpp
new file mode 100644 (file)
index 0000000..cbf0425
--- /dev/null
@@ -0,0 +1,9 @@
+// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s
+template <typename T> void f(T) {}
+
+void test() {
+  // FIXME: This emits only a declaration instead of a definition
+  // CHECK: @_Z1fIiEvT_
+  void (*p)(int) = &f;
+}
+// CHECK-disabled: define linkonce_odr void @_Z1fIiEvT_