Author: rsmith Date: Wed Nov 30 20:11:49 2016 New Revision: 288301 URL: http://llvm.org/viewvc/llvm-project?rev=288301&view=rev Log: PR31081: ignore exception specifications when deducing function template arguments from a declaration; despite what the standard says, this form of deduction should not be considering exception specifications.
Modified: cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=288301&r1=288300&r2=288301&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Wed Nov 30 20:11:49 2016 @@ -6515,7 +6515,12 @@ public: // C++ Template Argument Deduction (C++ [temp.deduct]) //===--------------------------------------------------------------------===// - QualType adjustCCAndNoReturn(QualType ArgFunctionType, QualType FunctionType); + /// Adjust the type \p ArgFunctionType to match the calling convention, + /// noreturn, and optionally the exception specification of \p FunctionType. + /// Deduction often wants to ignore these properties when matching function + /// types. + QualType adjustCCAndNoReturn(QualType ArgFunctionType, QualType FunctionType, + bool AdjustExceptionSpec = false); /// \brief Describes the result of template argument deduction. /// @@ -6624,7 +6629,7 @@ public: QualType ArgFunctionType, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, - bool InOverloadResolution = false); + bool IsAddressOfFunction = false); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, @@ -6637,7 +6642,7 @@ public: TemplateArgumentListInfo *ExplicitTemplateArgs, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, - bool InOverloadResolution = false); + bool IsAddressOfFunction = false); /// \brief Substitute Replacement for \p auto in \p TypeWithAuto QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement); Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=288301&r1=288300&r2=288301&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Nov 30 20:11:49 2016 @@ -2319,8 +2319,6 @@ bool Sema::FindAllocationFunctions(Sourc // To perform this comparison, we compute the function type that // the deallocation function should have, and use that type both // for template argument deduction and for comparison purposes. - // - // FIXME: this comparison should ignore CC and the like. QualType ExpectedFunctionType; { const FunctionProtoType *Proto @@ -2334,7 +2332,6 @@ bool Sema::FindAllocationFunctions(Sourc FunctionProtoType::ExtProtoInfo EPI; // FIXME: This is not part of the standard's rule. EPI.Variadic = Proto->isVariadic(); - EPI.ExceptionSpec.Type = EST_BasicNoexcept; ExpectedFunctionType = Context.getFunctionType(Context.VoidTy, ArgTypes, EPI); @@ -2344,8 +2341,8 @@ bool Sema::FindAllocationFunctions(Sourc DEnd = FoundDelete.end(); D != DEnd; ++D) { FunctionDecl *Fn = nullptr; - if (FunctionTemplateDecl *FnTmpl - = dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) { + if (FunctionTemplateDecl *FnTmpl = + dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) { // Perform template argument deduction to try to match the // expected function type. TemplateDeductionInfo Info(StartLoc); @@ -2355,7 +2352,10 @@ bool Sema::FindAllocationFunctions(Sourc } else Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl()); - if (Context.hasSameType(Fn->getType(), ExpectedFunctionType)) + if (Context.hasSameType(adjustCCAndNoReturn(Fn->getType(), + ExpectedFunctionType, + /*AdjustExcpetionSpec*/true), + ExpectedFunctionType)) Matches.push_back(std::make_pair(D.getPair(), Fn)); } Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=288301&r1=288300&r2=288301&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Nov 30 20:11:49 2016 @@ -10572,7 +10572,7 @@ private: = S.DeduceTemplateArguments(FunctionTemplate, &OvlExplicitTemplateArgs, TargetFunctionType, Specialization, - Info, /*InOverloadResolution=*/true)) { + Info, /*IsAddressOfFunction*/true)) { // Make a note of the failed deduction for diagnostics. FailedCandidates.addCandidate() .set(CurAccessFunPair, FunctionTemplate->getTemplatedDecl(), @@ -10975,7 +10975,7 @@ Sema::ResolveSingleFunctionTemplateSpeci if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs, Specialization, Info, - /*InOverloadResolution=*/true)) { + /*IsAddressOfFunction*/true)) { // Make a note of the failed deduction for diagnostics. // TODO: Actually use the failed-deduction info? FailedCandidates.addCandidate() Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=288301&r1=288300&r2=288301&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Nov 30 20:11:49 2016 @@ -8075,7 +8075,8 @@ DeclResult Sema::ActOnExplicitInstantiat NamedDecl *Prev = *P; if (!HasExplicitTemplateArgs) { if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) { - QualType Adjusted = adjustCCAndNoReturn(R, Method->getType()); + QualType Adjusted = adjustCCAndNoReturn(R, Method->getType(), + /*AdjustExceptionSpec*/true); if (Context.hasSameUnqualifiedType(Method->getType(), Adjusted)) { Matches.clear(); Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=288301&r1=288300&r2=288301&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Nov 30 20:11:49 2016 @@ -3571,25 +3571,42 @@ Sema::TemplateDeductionResult Sema::Dedu } QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType, - QualType FunctionType) { + QualType FunctionType, + bool AdjustExceptionSpec) { if (ArgFunctionType.isNull()) return ArgFunctionType; const FunctionProtoType *FunctionTypeP = FunctionType->castAs<FunctionProtoType>(); - CallingConv CC = FunctionTypeP->getCallConv(); - bool NoReturn = FunctionTypeP->getNoReturnAttr(); const FunctionProtoType *ArgFunctionTypeP = ArgFunctionType->getAs<FunctionProtoType>(); - if (ArgFunctionTypeP->getCallConv() == CC && - ArgFunctionTypeP->getNoReturnAttr() == NoReturn) + + FunctionProtoType::ExtProtoInfo EPI = ArgFunctionTypeP->getExtProtoInfo(); + bool Rebuild = false; + + CallingConv CC = FunctionTypeP->getCallConv(); + if (EPI.ExtInfo.getCC() != CC) { + EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC); + Rebuild = true; + } + + bool NoReturn = FunctionTypeP->getNoReturnAttr(); + if (EPI.ExtInfo.getNoReturn() != NoReturn) { + EPI.ExtInfo = EPI.ExtInfo.withNoReturn(NoReturn); + Rebuild = true; + } + + if (AdjustExceptionSpec && (FunctionTypeP->hasExceptionSpec() || + ArgFunctionTypeP->hasExceptionSpec())) { + EPI.ExceptionSpec = FunctionTypeP->getExtProtoInfo().ExceptionSpec; + Rebuild = true; + } + + if (!Rebuild) return ArgFunctionType; - FunctionType::ExtInfo EI = ArgFunctionTypeP->getExtInfo().withCallingConv(CC); - EI = EI.withNoReturn(NoReturn); - ArgFunctionTypeP = - cast<FunctionProtoType>(Context.adjustFunctionType(ArgFunctionTypeP, EI)); - return QualType(ArgFunctionTypeP, 0); + return Context.getFunctionType(ArgFunctionTypeP->getReturnType(), + ArgFunctionTypeP->getParamTypes(), EPI); } /// \brief Deduce template arguments when taking the address of a function @@ -3614,14 +3631,17 @@ QualType Sema::adjustCCAndNoReturn(QualT /// \param Info the argument will be updated to provide additional information /// about template argument deduction. /// +/// \param IsAddressOfFunction If \c true, we are deducing as part of taking +/// the address of a function template per [temp.deduct.funcaddr] and +/// [over.over]. If \c false, we are looking up a function template +/// specialization based on its signature, per [temp.deduct.decl]. +/// /// \returns the result of template argument deduction. -Sema::TemplateDeductionResult -Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - TemplateArgumentListInfo *ExplicitTemplateArgs, - QualType ArgFunctionType, - FunctionDecl *&Specialization, - TemplateDeductionInfo &Info, - bool InOverloadResolution) { +Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, + FunctionDecl *&Specialization, TemplateDeductionInfo &Info, + bool IsAddressOfFunction) { if (FunctionTemplate->isInvalidDecl()) return TDK_Invalid; @@ -3629,8 +3649,13 @@ Sema::DeduceTemplateArguments(FunctionTe TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); QualType FunctionType = Function->getType(); - if (!InOverloadResolution) - ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType); + + // When taking the address of a function, we require convertibility of + // the resulting function type. Otherwise, we allow arbitrary mismatches + // of calling convention, noreturn, and noexcept. + if (!IsAddressOfFunction) + ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType, + /*AdjustExceptionSpec*/true); // Substitute any explicit template arguments. LocalInstantiationScope InstScope(*this); @@ -3655,9 +3680,11 @@ Sema::DeduceTemplateArguments(FunctionTe Deduced.resize(TemplateParams->size()); // If the function has a deduced return type, substitute it for a dependent - // type so that we treat it as a non-deduced context in what follows. + // type so that we treat it as a non-deduced context in what follows. If we + // are looking up by signature, the signature type should also have a deduced + // return type, which we instead expect to exactly match. bool HasDeducedReturnType = false; - if (getLangOpts().CPlusPlus14 && InOverloadResolution && + if (getLangOpts().CPlusPlus14 && IsAddressOfFunction && Function->getReturnType()->getContainedAutoType()) { FunctionType = SubstAutoType(FunctionType, Context.DependentTy); HasDeducedReturnType = true; @@ -3665,7 +3692,8 @@ Sema::DeduceTemplateArguments(FunctionTe if (!ArgFunctionType.isNull()) { unsigned TDF = TDF_TopLevelParameterTypeList; - if (InOverloadResolution) TDF |= TDF_InOverloadResolution; + if (IsAddressOfFunction) + TDF |= TDF_InOverloadResolution; // Deduce template arguments from the function type. if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, @@ -3696,16 +3724,27 @@ Sema::DeduceTemplateArguments(FunctionTe !ResolveExceptionSpec(Info.getLocation(), SpecializationFPT)) return TDK_MiscellaneousDeductionFailure; + // Adjust the exception specification of the argument again to match the + // substituted and resolved type we just formed. (Calling convention and + // noreturn can't be dependent, so we don't actually need this for them + // right now.) + QualType SpecializationType = Specialization->getType(); + if (!IsAddressOfFunction) + ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, SpecializationType, + /*AdjustExceptionSpec*/true); + // If the requested function type does not match the actual type of the // specialization with respect to arguments of compatible pointer to function // types, template argument deduction fails. if (!ArgFunctionType.isNull()) { - if (InOverloadResolution && !isSameOrCompatibleFunctionType( - Context.getCanonicalType(Specialization->getType()), - Context.getCanonicalType(ArgFunctionType))) + if (IsAddressOfFunction && + !isSameOrCompatibleFunctionType( + Context.getCanonicalType(SpecializationType), + Context.getCanonicalType(ArgFunctionType))) return TDK_MiscellaneousDeductionFailure; - else if(!InOverloadResolution && - !Context.hasSameType(Specialization->getType(), ArgFunctionType)) + + if (!IsAddressOfFunction && + !Context.hasSameType(SpecializationType, ArgFunctionType)) return TDK_MiscellaneousDeductionFailure; } @@ -3977,16 +4016,22 @@ Sema::DeduceTemplateArguments(FunctionTe /// \param Info the argument will be updated to provide additional information /// about template argument deduction. /// +/// \param IsAddressOfFunction If \c true, we are deducing as part of taking +/// the address of a function template in a context where we do not have a +/// target type, per [over.over]. If \c false, we are looking up a function +/// template specialization based on its signature, which only happens when +/// deducing a function parameter type from an argument that is a template-id +/// naming a function template specialization. +/// /// \returns the result of template argument deduction. -Sema::TemplateDeductionResult -Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - TemplateArgumentListInfo *ExplicitTemplateArgs, - FunctionDecl *&Specialization, - TemplateDeductionInfo &Info, - bool InOverloadResolution) { +Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, + FunctionDecl *&Specialization, TemplateDeductionInfo &Info, + bool IsAddressOfFunction) { return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, QualType(), Specialization, Info, - InOverloadResolution); + IsAddressOfFunction); } namespace { Modified: cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp?rev=288301&r1=288300&r2=288301&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp (original) +++ cfe/trunk/test/SemaCXX/cxx1z-noexcept-function-type.cpp Wed Nov 30 20:11:49 2016 @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -std=c++14 -verify %s -// RUN: %clang_cc1 -std=c++1z -verify %s +// RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions %s +// RUN: %clang_cc1 -std=c++1z -verify -fexceptions -fcxx-exceptions %s #if __cplusplus > 201402L @@ -106,3 +106,47 @@ namespace Builtins { typedef int arr[strcmp("bar", "foo") + 4 * strncmp("foo", "bar", 4)]; typedef int arr[3]; } + +namespace ExplicitInstantiation { + template<typename T> void f() noexcept {} + template<typename T> struct X { void f() noexcept {} }; + template void f<int>(); + template void X<int>::f(); +} + +namespace ConversionFunction { + struct A { template<typename T> operator T() noexcept; }; + int a = A().operator int(); +} + +using size_t = decltype(sizeof(0)); + +namespace OperatorDelete { + struct W {}; + struct X {}; + struct Y {}; + struct Z {}; + template<bool N, bool D> struct T {}; +} +void *operator new(size_t, OperatorDelete::W) noexcept(false); +void operator delete(void*, OperatorDelete::W) noexcept(false) = delete; // expected-note {{here}} +void *operator new(size_t, OperatorDelete::X) noexcept(false); +void operator delete(void*, OperatorDelete::X) noexcept(true) = delete; // expected-note {{here}} +void *operator new(size_t, OperatorDelete::Y) noexcept(true); +void operator delete(void*, OperatorDelete::Y) noexcept(false) = delete; // expected-note {{here}} +void *operator new(size_t, OperatorDelete::Z) noexcept(true); +void operator delete(void*, OperatorDelete::Z) noexcept(true) = delete; // expected-note {{here}} +template<bool N, bool D> void *operator new(size_t, OperatorDelete::T<N, D>) noexcept(N); +template<bool N, bool D> void operator delete(void*, OperatorDelete::T<N, D>) noexcept(D) = delete; // expected-note 4{{here}} +namespace OperatorDelete { + struct A { A(); }; + A *w = new (W{}) A; // expected-error {{deleted function}} + A *x = new (X{}) A; // expected-error {{deleted function}} + A *y = new (Y{}) A; // expected-error {{deleted function}} + A *z = new (Z{}) A; // expected-error {{deleted function}} + + A *t00 = new (T<false, false>{}) A; // expected-error {{deleted function}} + A *t01 = new (T<false, true>{}) A; // expected-error {{deleted function}} + A *t10 = new (T<true, false>{}) A; // expected-error {{deleted function}} + A *t11 = new (T<true, true>{}) A; // expected-error {{deleted function}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits