diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 8ebe5ef6fc83..1cadcecd8818 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -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, diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 7fc27a44f7b6..d56c426d00ab 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -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); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index ecadcd904e28..5f874e8dbc95 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -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(E)) { - FixOverloadedFunctionReference(PE->getSubExpr(), Fn); + bool ret = FixOverloadedFunctionReference(PE->getSubExpr(), Fn); E->setType(PE->getSubExpr()->getType()); + return ret; } else if (UnaryOperator *UnOp = dyn_cast(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(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(E)) { assert((isa(DR->getDecl()) || isa(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/clang/test/CodeGenCXX/address-of-fntemplate.cpp b/clang/test/CodeGenCXX/address-of-fntemplate.cpp new file mode 100644 index 000000000000..cbf042551deb --- /dev/null +++ b/clang/test/CodeGenCXX/address-of-fntemplate.cpp @@ -0,0 +1,9 @@ +// RUN: clang-cc %s -emit-llvm -o - | FileCheck %s +template 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_