diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 50dfeebdbcde..970e8bc6c770 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -635,7 +635,8 @@ static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) { return isa(Decl) || isa(Decl) || // C++ 3.10p2: An lvalue refers to an object or function. (Ctx.getLangOptions().CPlusPlus && - (isa(Decl) || isa(Decl))); + (isa(Decl) || isa(Decl) || + isa(Decl))); } /// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an @@ -659,7 +660,7 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { // first, check the type (C99 6.3.2.1). Expressions with function // type in C are not lvalues, but they can be lvalues in C++. - if (TR->isFunctionType()) + if (TR->isFunctionType() || TR == Ctx.OverloadTy) return LV_NotObjectType; // Allow qualified void which is an incomplete type other than void (yuck). diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 11c0c25f2636..58fccc3e01e7 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2350,7 +2350,22 @@ public: DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, TemplateDeductionInfo &Info); - + + TemplateDeductionResult + SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + llvm::SmallVectorImpl &Deduced, + llvm::SmallVectorImpl &ParamTypes, + QualType *FunctionType, + TemplateDeductionInfo &Info); + + TemplateDeductionResult + FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, + llvm::SmallVectorImpl &Deduced, + FunctionDecl *&Specialization, + TemplateDeductionInfo &Info); + TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, bool HasExplicitTemplateArgs, @@ -2359,6 +2374,15 @@ public: Expr **Args, unsigned NumArgs, FunctionDecl *&Specialization, TemplateDeductionInfo &Info); + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + QualType ArgFunctionType, + FunctionDecl *&Specialization, + TemplateDeductionInfo &Info); void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs, llvm::SmallVectorImpl &Deduced); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 2bb49d5400f8..8ede57c59dfe 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4684,7 +4684,8 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { << "register variable" << op->getSourceRange(); return QualType(); } - } else if (isa(dcl)) { + } else if (isa(dcl) || + isa(dcl)) { return Context.OverloadTy; } else if (isa(dcl)) { // Okay: we can take the address of a field. diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index e64080ea6a21..b7edc0149ea9 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -3702,7 +3702,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } // We only look at pointers or references to functions. - if (!FunctionType->isFunctionType()) + FunctionType = Context.getCanonicalType(FunctionType.getUnqualifiedType()); + if (!FunctionType->isFunctionType()) return 0; // Find the actual overloaded function declaration. @@ -3722,44 +3723,69 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, } // Try to dig out the overloaded function. - if (DeclRefExpr *DR = dyn_cast(OvlExpr)) + FunctionTemplateDecl *FunctionTemplate = 0; + if (DeclRefExpr *DR = dyn_cast(OvlExpr)) { Ovl = dyn_cast(DR->getDecl()); + FunctionTemplate = dyn_cast(DR->getDecl()); + } - // If there's no overloaded function declaration, we're done. - if (!Ovl) + // If there's no overloaded function declaration or function template, + // we're done. + if (!Ovl && !FunctionTemplate) return 0; + OverloadIterator Fun; + if (Ovl) + Fun = Ovl; + else + Fun = FunctionTemplate; + // 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) { + // FIXME: We still need to cope with duplicates, partial ordering, etc. + for (OverloadIterator FunEnd; Fun != FunEnd; ++Fun) { // C++ [over.over]p3: // Non-member functions and static member functions match // targets of type "pointer-to-function" or "reference-to-function." // Nonstatic member functions match targets of // type "pointer-to-member-function." // Note that according to DR 247, the containing class does not matter. + + if (FunctionTemplateDecl *FunctionTemplate + = dyn_cast(*Fun)) { + // C++ [temp.deduct.funcaddr]p1: + // Template arguments can be deduced from the type specified when + // taking the address of an overloaded function (13.4). The function + // template’s function type and the specified type are used as the + // types of P and A, and the deduction is done as described in + // 14.8.2.4. + FunctionDecl *Specialization = 0; + TemplateDeductionInfo Info(Context); + if (TemplateDeductionResult Result + = DeduceTemplateArguments(FunctionTemplate, /*FIXME*/false, + /*FIXME:*/0, /*FIXME:*/0, + FunctionType, Specialization, Info)) { + // FIXME: make a note of the failed deduction for diagnostics. + (void)Result; + } else { + assert(FunctionType + == Context.getCanonicalType(Specialization->getType())); + return Specialization; + } + } + if (CXXMethodDecl *Method = dyn_cast(*Fun)) { // Skip non-static functions when converting to pointer, and static // when converting to member pointer. if (Method->isStatic() == IsMember) continue; - } else if (IsMember) + } else if (IsMember) // FIXME: member templates continue; if (FunctionDecl *FunDecl = dyn_cast(*Fun)) { if (FunctionType == Context.getCanonicalType(FunDecl->getType())) return FunDecl; - } else { - unsigned DiagID - = PP.getDiagnostics().getCustomDiagID(Diagnostic::Warning, - "Clang does not yet support templated conversion functions"); - Diag(From->getLocStart(), DiagID); - } + } } return 0; @@ -4614,8 +4640,9 @@ void Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); E->setType(Context.getPointerType(UnOp->getSubExpr()->getType())); } else if (DeclRefExpr *DR = dyn_cast(E)) { - assert(isa(DR->getDecl()) && - "Expected overloaded function"); + assert((isa(DR->getDecl()) || + isa(DR->getDecl())) && + "Expected overloaded function or function template"); DR->setDecl(Fn); E->setType(Fn->getType()); } else if (MemberExpr *MemExpr = dyn_cast(E)) { diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index d294455ec6ab..f6f9d105d95d 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -956,7 +956,220 @@ static bool isSimpleTemplateIdType(QualType T) { return false; } - + +/// \brief Substitute the explicitly-provided template arguments into the +/// given function template according to C++ [temp.arg.explicit]. +/// +/// \param FunctionTemplate the function template into which the explicit +/// template arguments will be substituted. +/// +/// \param ExplicitTemplateArguments the explicitly-specified template +/// arguments. +/// +/// \param NumExplicitTemplateArguments the number of explicitly-specified +/// template arguments in @p ExplicitTemplateArguments. This value may be zero. +/// +/// \param Deduced the deduced template arguments, which will be populated +/// with the converted and checked explicit template arguments. +/// +/// \param ParamTypes will be populated with the instantiated function +/// parameters. +/// +/// \param FunctionType if non-NULL, the result type of the function template +/// will also be instantiated and the pointed-to value will be updated with +/// the instantiated function type. +/// +/// \param Info if substitution fails for any reason, this object will be +/// populated with more information about the failure. +/// +/// \returns TDK_Success if substitution was successful, or some failure +/// condition. +Sema::TemplateDeductionResult +Sema::SubstituteExplicitTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + llvm::SmallVectorImpl &Deduced, + llvm::SmallVectorImpl &ParamTypes, + QualType *FunctionType, + TemplateDeductionInfo &Info) { + FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); + TemplateParameterList *TemplateParams + = FunctionTemplate->getTemplateParameters(); + + if (NumExplicitTemplateArgs == 0) { + // No arguments to substitute; just copy over the parameter types and + // fill in the function type. + for (FunctionDecl::param_iterator P = Function->param_begin(), + PEnd = Function->param_end(); + P != PEnd; + ++P) + ParamTypes.push_back((*P)->getType()); + + if (FunctionType) + *FunctionType = Function->getType(); + return TDK_Success; + } + + // Substitution of the explicit template arguments into a function template + /// is a SFINAE context. Trap any errors that might occur. + SFINAETrap Trap(*this); + + // C++ [temp.arg.explicit]p3: + // Template arguments that are present shall be specified in the + // declaration order of their corresponding template-parameters. The + // template argument list shall not specify more template-arguments than + // there are corresponding template-parameters. + TemplateArgumentListBuilder Builder(TemplateParams, + NumExplicitTemplateArgs); + + // Enter a new template instantiation context where we check the + // explicitly-specified template arguments against this function template, + // and then substitute them into the function parameter types. + InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), + FunctionTemplate, Deduced.data(), Deduced.size(), + ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution); + if (Inst) + return TDK_InstantiationDepth; + + if (CheckTemplateArgumentList(FunctionTemplate, + SourceLocation(), SourceLocation(), + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + SourceLocation(), + true, + Builder) || Trap.hasErrorOccurred()) + return TDK_InvalidExplicitArguments; + + // Form the template argument list from the explicitly-specified + // template arguments. + TemplateArgumentList *ExplicitArgumentList + = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); + Info.reset(ExplicitArgumentList); + + // Instantiate the types of each of the function parameters given the + // explicitly-specified template arguments. + for (FunctionDecl::param_iterator P = Function->param_begin(), + PEnd = Function->param_end(); + P != PEnd; + ++P) { + QualType ParamType = InstantiateType((*P)->getType(), + *ExplicitArgumentList, + (*P)->getLocation(), + (*P)->getDeclName()); + if (ParamType.isNull() || Trap.hasErrorOccurred()) + return TDK_SubstitutionFailure; + + ParamTypes.push_back(ParamType); + } + + // If the caller wants a full function type back, instantiate the return + // type and form that function type. + if (FunctionType) { + // FIXME: exception-specifications? + const FunctionProtoType *Proto + = Function->getType()->getAsFunctionProtoType(); + assert(Proto && "Function template does not have a prototype?"); + + QualType ResultType = InstantiateType(Proto->getResultType(), + *ExplicitArgumentList, + Function->getTypeSpecStartLoc(), + Function->getDeclName()); + if (ResultType.isNull() || Trap.hasErrorOccurred()) + return TDK_SubstitutionFailure; + + *FunctionType = BuildFunctionType(ResultType, + ParamTypes.data(), ParamTypes.size(), + Proto->isVariadic(), + Proto->getTypeQuals(), + Function->getLocation(), + Function->getDeclName()); + if (FunctionType->isNull() || Trap.hasErrorOccurred()) + return TDK_SubstitutionFailure; + } + + // C++ [temp.arg.explicit]p2: + // Trailing template arguments that can be deduced (14.8.2) may be + // omitted from the list of explicit template-arguments. If all of the + // template arguments can be deduced, they may all be omitted; in this + // case, the empty template argument list <> itself may also be omitted. + // + // Take all of the explicitly-specified arguments and put them into the + // set of deduced template arguments. + Deduced.reserve(TemplateParams->size()); + for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) + Deduced.push_back(ExplicitArgumentList->get(I)); + + return TDK_Success; +} + +/// \brief Finish template argument deduction for a function template, +/// checking the deduced template arguments for completeness and forming +/// the function template specialization. +Sema::TemplateDeductionResult +Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, + llvm::SmallVectorImpl &Deduced, + FunctionDecl *&Specialization, + TemplateDeductionInfo &Info) { + TemplateParameterList *TemplateParams + = FunctionTemplate->getTemplateParameters(); + + // C++ [temp.deduct.type]p2: + // [...] or if any template argument remains neither deduced nor + // explicitly specified, template argument deduction fails. + TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size()); + for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { + if (Deduced[I].isNull()) { + Info.Param = makeTemplateParameter( + const_cast(TemplateParams->getParam(I))); + return TDK_Incomplete; + } + + Builder.Append(Deduced[I]); + } + + // Form the template argument list from the deduced template arguments. + TemplateArgumentList *DeducedArgumentList + = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); + Info.reset(DeducedArgumentList); + + // Template argument deduction for function templates in a SFINAE context. + // Trap any errors that might occur. + SFINAETrap Trap(*this); + + // Enter a new template instantiation context while we instantiate the + // actual function declaration. + InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), + FunctionTemplate, Deduced.data(), Deduced.size(), + ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); + if (Inst) + return TDK_InstantiationDepth; + + // Substitute the deduced template arguments into the function template + // declaration to produce the function template specialization. + Specialization = cast_or_null( + InstantiateDecl(FunctionTemplate->getTemplatedDecl(), + FunctionTemplate->getDeclContext(), + *DeducedArgumentList)); + if (!Specialization) + return TDK_SubstitutionFailure; + + // If the template argument list is owned by the function template + // specialization, release it. + if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList) + Info.take(); + + // There may have been an error that did not prevent us from constructing a + // declaration. Mark the declaration invalid and return with a substitution + // failure. + if (Trap.hasErrorOccurred()) { + Specialization->setInvalidDecl(true); + return TDK_SubstitutionFailure; + } + + return TDK_Success; +} + /// \brief Perform template argument deduction from a function call /// (C++ [temp.deduct.call]). /// @@ -1011,10 +1224,6 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, CheckArgs = Function->getNumParams(); } - // Template argument deduction for function templates in a SFINAE context. - // Trap any errors that might occur. - SFINAETrap Trap(*this); - // The types of the parameters from which we will perform template argument // deduction. TemplateParameterList *TemplateParams @@ -1022,71 +1231,22 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, llvm::SmallVector Deduced; llvm::SmallVector ParamTypes; if (NumExplicitTemplateArgs) { - // C++ [temp.arg.explicit]p3: - // Template arguments that are present shall be specified in the - // declaration order of their corresponding template-parameters. The - // template argument list shall not specify more template-arguments than - // there are corresponding template-parameters. - TemplateArgumentListBuilder Builder(TemplateParams, - NumExplicitTemplateArgs); - - // Enter a new template instantiation context where we check the - // explicitly-specified template arguments against this function template, - // and then substitute them into the function parameter types. - InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), - FunctionTemplate, Deduced.data(), Deduced.size(), - ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution); - if (Inst) - return TDK_InstantiationDepth; - - if (CheckTemplateArgumentList(FunctionTemplate, - SourceLocation(), SourceLocation(), - ExplicitTemplateArgs, - NumExplicitTemplateArgs, - SourceLocation(), - true, - Builder) || Trap.hasErrorOccurred()) - return TDK_InvalidExplicitArguments; - - // Form the template argument list from the explicitly-specified - // template arguments. - TemplateArgumentList *ExplicitArgumentList - = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); - Info.reset(ExplicitArgumentList); - - // Instantiate the types of each of the function parameters given the - // explicitly-specified template arguments. - for (FunctionDecl::param_iterator P = Function->param_begin(), - PEnd = Function->param_end(); - P != PEnd; - ++P) { - QualType ParamType = InstantiateType((*P)->getType(), - *ExplicitArgumentList, - (*P)->getLocation(), - (*P)->getDeclName()); - if (ParamType.isNull() || Trap.hasErrorOccurred()) - return TDK_SubstitutionFailure; - - ParamTypes.push_back(ParamType); - } - - // C++ [temp.arg.explicit]p2: - // Trailing template arguments that can be deduced (14.8.2) may be - // omitted from the list of explicit template- arguments. If all of the - // template arguments can be deduced, they may all be omitted; in this - // case, the empty template argument list <> itself may also be omitted. - // - // Take all of the explicitly-specified arguments and put them into the - // set of deduced template arguments. - Deduced.reserve(TemplateParams->size()); - for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) - Deduced.push_back(ExplicitArgumentList->get(I)); + TemplateDeductionResult Result = + SubstituteExplicitTemplateArguments(FunctionTemplate, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + Deduced, + ParamTypes, + 0, + Info); + if (Result) + return Result; } else { // Just fill in the parameter types from the function declaration. for (unsigned I = 0; I != CheckArgs; ++I) ParamTypes.push_back(Function->getParamDecl(I)->getType()); } - + // Deduce template arguments from the function parameters. Deduced.resize(TemplateParams->size()); for (unsigned I = 0; I != CheckArgs; ++I) { @@ -1173,65 +1333,81 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, // pointer parameters. } - // C++ [temp.deduct.type]p2: - // [...] or if any template argument remains neither deduced nor - // explicitly specified, template argument deduction fails. - TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size()); - for (unsigned I = 0, N = Deduced.size(); I != N; ++I) { - if (Deduced[I].isNull()) { - Decl *Param - = const_cast(TemplateParams->getParam(I)); - if (TemplateTypeParmDecl *TTP = dyn_cast(Param)) - Info.Param = TTP; - else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast(Param)) - Info.Param = NTTP; - else - Info.Param = cast(Param); - return TDK_Incomplete; - } - - Builder.Append(Deduced[I]); - } - - // Form the template argument list from the deduced template arguments. - TemplateArgumentList *DeducedArgumentList - = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true); - Info.reset(DeducedArgumentList); - - // Enter a new template instantiation context while we instantiate the - // actual function declaration. - InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(), - FunctionTemplate, Deduced.data(), Deduced.size(), - ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); - if (Inst) - return TDK_InstantiationDepth; - - // Substitute the deduced template arguments into the function template - // declaration to produce the function template specialization. - Specialization = cast_or_null( - InstantiateDecl(FunctionTemplate->getTemplatedDecl(), - FunctionTemplate->getDeclContext(), - *DeducedArgumentList)); - if (!Specialization) - return TDK_SubstitutionFailure; - - // If the template argument list is owned by the function template - // specialization, release it. - if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList) - Info.take(); - - // There may have been an error that did not prevent us from constructing a - // declaration. Mark the declaration invalid and return with a substitution - // failure. - if (Trap.hasErrorOccurred()) { - Specialization->setInvalidDecl(true); - return TDK_SubstitutionFailure; - } - - return TDK_Success; + return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, + Specialization, Info); } +/// \brief Deduce template arguments when taking the address of a function +/// template (C++ [temp.deduct.funcaddr]). +/// +/// \param FunctionTemplate the function template for which we are performing +/// template argument deduction. +/// +/// \param HasExplicitTemplateArgs whether any template arguments were +/// explicitly specified. +/// +/// \param ExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, +/// the explicitly-specified template arguments. +/// +/// \param NumExplicitTemplateArguments when @p HasExplicitTemplateArgs is true, +/// the number of explicitly-specified template arguments in +/// @p ExplicitTemplateArguments. This value may be zero. +/// +/// \param ArgFunctionType the function type that will be used as the +/// "argument" type (A) when performing template argument deduction from the +/// function template's function type. +/// +/// \param Specialization if template argument deduction was successful, +/// this will be set to the function template specialization produced by +/// template argument deduction. +/// +/// \param Info the argument will be updated to provide additional information +/// about template argument deduction. +/// +/// \returns the result of template argument deduction. +Sema::TemplateDeductionResult +Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + bool HasExplicitTemplateArgs, + const TemplateArgument *ExplicitTemplateArgs, + unsigned NumExplicitTemplateArgs, + QualType ArgFunctionType, + FunctionDecl *&Specialization, + TemplateDeductionInfo &Info) { + FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); + TemplateParameterList *TemplateParams + = FunctionTemplate->getTemplateParameters(); + QualType FunctionType = Function->getType(); + + // Substitute any explicit template arguments. + llvm::SmallVector Deduced; + llvm::SmallVector ParamTypes; + if (HasExplicitTemplateArgs) { + if (TemplateDeductionResult Result + = SubstituteExplicitTemplateArguments(FunctionTemplate, + ExplicitTemplateArgs, + NumExplicitTemplateArgs, + Deduced, ParamTypes, + &FunctionType, Info)) + return Result; + } + + // Template argument deduction for function templates in a SFINAE context. + // Trap any errors that might occur. + SFINAETrap Trap(*this); + + // Deduce template arguments from the function type. + Deduced.resize(TemplateParams->size()); + if (TemplateDeductionResult Result + = ::DeduceTemplateArguments(Context, TemplateParams, + FunctionType, ArgFunctionType, Info, + Deduced, 0)) + return Result; + + return FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, + Specialization, Info); +} + + static void MarkDeducedTemplateParameters(Sema &SemaRef, const TemplateArgument &TemplateArg, diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.funcaddr/p1.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.funcaddr/p1.cpp new file mode 100644 index 000000000000..0a496392a826 --- /dev/null +++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.funcaddr/p1.cpp @@ -0,0 +1,22 @@ +// RUN: clang-cc -fsyntax-only %s + +template + T f0(T, int); + +void test_f0() { + int (*f0a)(int, int) = f0; + int (*f0b)(int, int) = &f0; + float (*f0c)(float, int) = &f0; +} + +template T f1(T, int); +template T f1(T); + +void test_f1() { + float (*f1a)(float, int) = f1; + float (*f1b)(float, int) = &f1; + float (*f1c)(float) = f1; + float (*f1d)(float) = (f1); + float (*f1e)(float) = &f1; + float (*f1f)(float) = (&f1); +} \ No newline at end of file