r179680 - Fix PR15291: noreturn adjustment in overload resolution for function templates, from Alexander Zinenko!
Douglas Gregor
dgregor at apple.com
Wed Apr 17 01:45:08 PDT 2013
Author: dgregor
Date: Wed Apr 17 03:45:07 2013
New Revision: 179680
URL: http://llvm.org/viewvc/llvm-project?rev=179680&view=rev
Log:
Fix PR15291: noreturn adjustment in overload resolution for function templates, from Alexander Zinenko!
Modified:
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
cfe/trunk/test/SemaCXX/attr-noreturn.cpp
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=179680&r1=179679&r2=179680&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Apr 17 03:45:07 2013
@@ -1877,7 +1877,7 @@ public:
bool IsNoReturnConversion(QualType FromType, QualType ToType,
QualType &ResultTy);
bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
-
+ bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg);
ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
const VarDecl *NRVOCandidate,
@@ -5616,7 +5616,8 @@ public:
TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ArgFunctionType,
FunctionDecl *&Specialization,
- sema::TemplateDeductionInfo &Info);
+ sema::TemplateDeductionInfo &Info,
+ bool InOverloadResolution = false);
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
@@ -5628,7 +5629,8 @@ public:
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs,
FunctionDecl *&Specialization,
- sema::TemplateDeductionInfo &Info);
+ sema::TemplateDeductionInfo &Info,
+ bool InOverloadResolution = false);
/// \brief Result type of DeduceAutoType.
enum DeduceAutoResult {
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=179680&r1=179679&r2=179680&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed Apr 17 03:45:07 2013
@@ -9134,17 +9134,19 @@ private:
= S.DeduceTemplateArguments(FunctionTemplate,
&OvlExplicitTemplateArgs,
TargetFunctionType, Specialization,
- Info)) {
+ Info, /*InOverloadResolution=*/true)) {
// FIXME: make a note of the failed deduction for diagnostics.
(void)Result;
return false;
}
- // Template argument deduction ensures that we have an exact match.
+ // Template argument deduction ensures that we have an exact match or
+ // compatible pointer-to-function arguments that would be adjusted by ICS.
// This function template specicalization works.
Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl());
- assert(TargetFunctionType
- == Context.getCanonicalType(Specialization->getType()));
+ assert(S.isSameOrCompatibleFunctionType(
+ Context.getCanonicalType(Specialization->getType()),
+ Context.getCanonicalType(TargetFunctionType)));
Matches.push_back(std::make_pair(CurAccessFunPair, Specialization));
return true;
}
@@ -9409,7 +9411,8 @@ Sema::ResolveSingleFunctionTemplateSpeci
TemplateDeductionInfo Info(ovl->getNameLoc());
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
- Specialization, Info)) {
+ Specialization, Info,
+ /*InOverloadResolution=*/true)) {
// FIXME: make a note of the failed deduction for diagnostics.
(void)Result;
continue;
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=179680&r1=179679&r2=179680&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Apr 17 03:45:07 2013
@@ -52,7 +52,11 @@ namespace clang {
TDF_SkipNonDependent = 0x08,
/// \brief Whether we are performing template argument deduction for
/// parameters and arguments in a top-level template argument
- TDF_TopLevelParameterTypeList = 0x10
+ TDF_TopLevelParameterTypeList = 0x10,
+ /// \brief Within template argument deduction from overload resolution per
+ /// C++ [over.over] allow matching function types that are compatible in
+ /// terms of noreturn and default calling convention adjustments.
+ TDF_InOverloadResolution = 0x20
};
}
@@ -867,6 +871,32 @@ static bool hasInconsistentOrSupersetQua
== ParamQs.getCVRQualifiers());
}
+/// \brief Compare types for equality with respect to possibly compatible
+/// function types (noreturn adjustment, implicit calling conventions). If any
+/// of parameter and argument is not a function, just perform type comparison.
+///
+/// \param Param the template parameter type.
+///
+/// \param Arg the argument type.
+bool Sema::isSameOrCompatibleFunctionType(CanQualType Param,
+ CanQualType Arg) {
+ const FunctionType *ParamFunction = Param->getAs<FunctionType>(),
+ *ArgFunction = Arg->getAs<FunctionType>();
+
+ // Just compare if not functions.
+ if (!ParamFunction || !ArgFunction)
+ return Param == Arg;
+
+ // Noreturn adjustment.
+ QualType AdjustedParam;
+ if (IsNoReturnConversion(Param, Arg, AdjustedParam))
+ return Arg == Context.getCanonicalType(AdjustedParam);
+
+ // FIXME: Compatible calling conventions.
+
+ return Param == Arg;
+}
+
/// \brief Deduce the template arguments by comparing the parameter type and
/// the argument type (C++ [temp.deduct.type]).
///
@@ -1103,6 +1133,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema
return Sema::TDK_Success;
// Check the cv-qualifiers on the parameter and argument types.
+ CanQualType CanParam = S.Context.getCanonicalType(Param);
+ CanQualType CanArg = S.Context.getCanonicalType(Arg);
if (!(TDF & TDF_IgnoreQualifiers)) {
if (TDF & TDF_ParamWithReferenceType) {
if (hasInconsistentOrSupersetQualifiersOf(Param, Arg))
@@ -1114,14 +1146,25 @@ DeduceTemplateArgumentsByTypeMatch(Sema
// If the parameter type is not dependent, there is nothing to deduce.
if (!Param->isDependentType()) {
- if (!(TDF & TDF_SkipNonDependent) && Param != Arg)
- return Sema::TDK_NonDeducedMismatch;
-
+ if (!(TDF & TDF_SkipNonDependent)) {
+ bool NonDeduced = (TDF & TDF_InOverloadResolution)?
+ !S.isSameOrCompatibleFunctionType(CanParam, CanArg) :
+ Param != Arg;
+ if (NonDeduced) {
+ return Sema::TDK_NonDeducedMismatch;
+ }
+ }
return Sema::TDK_Success;
}
- } else if (!Param->isDependentType() &&
- Param.getUnqualifiedType() == Arg.getUnqualifiedType()) {
- return Sema::TDK_Success;
+ } else if (!Param->isDependentType()) {
+ CanQualType ParamUnqualType = CanParam.getUnqualifiedType(),
+ ArgUnqualType = CanArg.getUnqualifiedType();
+ bool Success = (TDF & TDF_InOverloadResolution)?
+ S.isSameOrCompatibleFunctionType(ParamUnqualType,
+ ArgUnqualType) :
+ ParamUnqualType == ArgUnqualType;
+ if (Success)
+ return Sema::TDK_Success;
}
switch (Param->getTypeClass()) {
@@ -3316,7 +3359,8 @@ Sema::DeduceTemplateArguments(FunctionTe
TemplateArgumentListInfo *ExplicitTemplateArgs,
QualType ArgFunctionType,
FunctionDecl *&Specialization,
- TemplateDeductionInfo &Info) {
+ TemplateDeductionInfo &Info,
+ bool InOverloadResolution) {
if (FunctionTemplate->isInvalidDecl())
return TDK_Invalid;
@@ -3348,11 +3392,13 @@ Sema::DeduceTemplateArguments(FunctionTe
Deduced.resize(TemplateParams->size());
if (!ArgFunctionType.isNull()) {
+ unsigned TDF = TDF_TopLevelParameterTypeList;
+ if (InOverloadResolution) TDF |= TDF_InOverloadResolution;
// Deduce template arguments from the function type.
if (TemplateDeductionResult Result
= DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
- FunctionType, ArgFunctionType, Info,
- Deduced, TDF_TopLevelParameterTypeList))
+ FunctionType, ArgFunctionType,
+ Info, Deduced, TDF))
return Result;
}
@@ -3363,10 +3409,17 @@ Sema::DeduceTemplateArguments(FunctionTe
return Result;
// If the requested function type does not match the actual type of the
- // specialization, template argument deduction fails.
- if (!ArgFunctionType.isNull() &&
- !Context.hasSameType(ArgFunctionType, Specialization->getType()))
- return TDK_MiscellaneousDeductionFailure;
+ // 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)))
+ return TDK_MiscellaneousDeductionFailure;
+ else if(!InOverloadResolution &&
+ !Context.hasSameType(Specialization->getType(), ArgFunctionType))
+ return TDK_MiscellaneousDeductionFailure;
+ }
return TDK_Success;
}
@@ -3499,9 +3552,11 @@ Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo *ExplicitTemplateArgs,
FunctionDecl *&Specialization,
- TemplateDeductionInfo &Info) {
+ TemplateDeductionInfo &Info,
+ bool InOverloadResolution) {
return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
- QualType(), Specialization, Info);
+ QualType(), Specialization, Info,
+ InOverloadResolution);
}
namespace {
Modified: cfe/trunk/test/SemaCXX/attr-noreturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-noreturn.cpp?rev=179680&r1=179679&r2=179680&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/attr-noreturn.cpp (original)
+++ cfe/trunk/test/SemaCXX/attr-noreturn.cpp Wed Apr 17 03:45:07 2013
@@ -80,3 +80,86 @@ namespace PR12948 {
template<typename> void wibble() __attribute__((__noreturn__));
template<typename> voidfn wibble;
}
+
+// PR15291
+// Overload resolution per over.over should allow implicit noreturn adjustment.
+namespace PR15291 {
+ __attribute__((noreturn)) void foo(int) {}
+ __attribute__((noreturn)) void foo(double) {}
+
+ template <typename T>
+ __attribute__((noreturn)) void bar(T) {}
+
+ void baz(int) {}
+ void baz(double) {}
+
+ template <typename T>
+ void qux(T) {}
+
+ // expected-note at +5 {{candidate function [with T = void (*)(int) __attribute__((noreturn))] not viable: no overload of 'baz' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+ // expected-note at +4 {{candidate function [with T = void (*)(int) __attribute__((noreturn))] not viable: no overload of 'qux' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+ // expected-note at +3 {{candidate function [with T = void (*)(int) __attribute__((noreturn))] not viable: no overload of 'bar' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+ // expected-note at +2 {{candidate function [with T = void (*)(int)] not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
+ // expected-note at +1 {{candidate function [with T = void (int)] not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
+ template <typename T> void accept_T(T) {}
+
+ // expected-note at +1 {{candidate function not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
+ void accept_fptr(void (*f)(int)) {
+ f(42);
+ }
+
+ // expected-note at +2 {{candidate function not viable: no overload of 'baz' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+ // expected-note at +1 {{candidate function not viable: no overload of 'qux' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
+ void accept_noreturn_fptr(void __attribute__((noreturn)) (*f)(int)) {
+ f(42);
+ }
+
+ typedef void (*fptr_t)(int);
+ typedef void __attribute__((noreturn)) (*fptr_noreturn_t)(int);
+
+ // expected-note at +1 {{candidate function not viable: no overload of 'bar' matching 'fptr_t' (aka 'void (*)(int)') for 1st argument}}
+ void accept_fptr_t(fptr_t f) {
+ f(42);
+ }
+
+ // expected-note at +2 {{candidate function not viable: no overload of 'baz' matching 'fptr_noreturn_t' (aka 'void (*)(int) __attribute__((noreturn))') for 1st argument}}
+ // expected-note at +1 {{candidate function not viable: no overload of 'qux' matching 'fptr_noreturn_t' (aka 'void (*)(int) __attribute__((noreturn))') for 1st argument}}
+ void accept_fptr_noreturn_t(fptr_noreturn_t f) {
+ f(42);
+ }
+
+ // Stripping noreturn should work if everything else is correct.
+ void strip_noreturn() {
+ accept_fptr(foo);
+ accept_fptr(bar<int>);
+ accept_fptr(bar<double>); // expected-error {{no matching function for call to 'accept_fptr'}}
+
+ accept_fptr_t(foo);
+ accept_fptr_t(bar<int>);
+ accept_fptr_t(bar<double>); // expected-error {{no matching function for call to 'accept_fptr_t'}}
+
+ accept_T<void __attribute__((noreturn)) (*)(int)>(foo);
+ accept_T<void __attribute__((noreturn)) (*)(int)>(bar<int>);
+ accept_T<void __attribute__((noreturn)) (*)(int)>(bar<double>); // expected-error {{no matching function for call to 'accept_T'}}
+
+ accept_T<void (*)(int)>(foo);
+ accept_T<void (*)(int)>(bar<int>);
+ accept_T<void (*)(int)>(bar<double>); // expected-error {{no matching function for call to 'accept_T'}}
+
+ accept_T<void (int)>(foo);
+ accept_T<void (int)>(bar<int>);
+ accept_T<void (int)>(bar<double>); // expected-error {{no matching function for call to 'accept_T'}}
+ }
+
+ // Introducing noreturn should not work.
+ void introduce_noreturn() {
+ accept_noreturn_fptr(baz); // expected-error {{no matching function for call to 'accept_noreturn_fptr'}}
+ accept_noreturn_fptr(qux<int>); // expected-error {{no matching function for call to 'accept_noreturn_fptr'}}
+
+ accept_fptr_noreturn_t(baz); // expected-error {{no matching function for call to 'accept_fptr_noreturn_t'}}
+ accept_fptr_noreturn_t(qux<int>); // expected-error {{no matching function for call to 'accept_fptr_noreturn_t'}}
+
+ accept_T<void __attribute__((noreturn)) (*)(int)>(baz); // expected-error {{no matching function for call to 'accept_T'}}
+ accept_T<void __attribute__((noreturn)) (*)(int)>(qux<int>); // expected-error {{no matching function for call to 'accept_T'}}
+ }
+}
More information about the cfe-commits
mailing list