mirror of https://github.com/microsoft/clang.git
[c++1z] Support deducing B in noexcept(B).
This is not required by the standard (yet), but there seems to be reasonable support for this being a defect according to CWG discussion, and libstdc++ 7.1 relies on it working. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@304946 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
a2380ee70a
commit
410ea620fd
|
@ -7555,6 +7555,10 @@ public:
|
||||||
unsigned ThisTypeQuals);
|
unsigned ThisTypeQuals);
|
||||||
void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
|
void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
|
||||||
const MultiLevelTemplateArgumentList &Args);
|
const MultiLevelTemplateArgumentList &Args);
|
||||||
|
bool SubstExceptionSpec(SourceLocation Loc,
|
||||||
|
FunctionProtoType::ExceptionSpecInfo &ESI,
|
||||||
|
SmallVectorImpl<QualType> &ExceptionStorage,
|
||||||
|
const MultiLevelTemplateArgumentList &Args);
|
||||||
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
|
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
|
||||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||||
int indexAdjustment,
|
int indexAdjustment,
|
||||||
|
|
|
@ -56,8 +56,12 @@ namespace clang {
|
||||||
TDF_TopLevelParameterTypeList = 0x10,
|
TDF_TopLevelParameterTypeList = 0x10,
|
||||||
/// \brief Within template argument deduction from overload resolution per
|
/// \brief Within template argument deduction from overload resolution per
|
||||||
/// C++ [over.over] allow matching function types that are compatible in
|
/// C++ [over.over] allow matching function types that are compatible in
|
||||||
/// terms of noreturn and default calling convention adjustments.
|
/// terms of noreturn and default calling convention adjustments, or
|
||||||
TDF_InOverloadResolution = 0x20
|
/// similarly matching a declared template specialization against a
|
||||||
|
/// possible template, per C++ [temp.deduct.decl]. In either case, permit
|
||||||
|
/// deduction where the parameter is a function type that can be converted
|
||||||
|
/// to the argument type.
|
||||||
|
TDF_AllowCompatibleFunctionType = 0x20,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1306,9 +1310,10 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
|
||||||
// If the parameter type is not dependent, there is nothing to deduce.
|
// If the parameter type is not dependent, there is nothing to deduce.
|
||||||
if (!Param->isDependentType()) {
|
if (!Param->isDependentType()) {
|
||||||
if (!(TDF & TDF_SkipNonDependent)) {
|
if (!(TDF & TDF_SkipNonDependent)) {
|
||||||
bool NonDeduced = (TDF & TDF_InOverloadResolution)?
|
bool NonDeduced =
|
||||||
!S.isSameOrCompatibleFunctionType(CanParam, CanArg) :
|
(TDF & TDF_AllowCompatibleFunctionType)
|
||||||
Param != Arg;
|
? !S.isSameOrCompatibleFunctionType(CanParam, CanArg)
|
||||||
|
: Param != Arg;
|
||||||
if (NonDeduced) {
|
if (NonDeduced) {
|
||||||
return Sema::TDK_NonDeducedMismatch;
|
return Sema::TDK_NonDeducedMismatch;
|
||||||
}
|
}
|
||||||
|
@ -1318,10 +1323,10 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
|
||||||
} else if (!Param->isDependentType()) {
|
} else if (!Param->isDependentType()) {
|
||||||
CanQualType ParamUnqualType = CanParam.getUnqualifiedType(),
|
CanQualType ParamUnqualType = CanParam.getUnqualifiedType(),
|
||||||
ArgUnqualType = CanArg.getUnqualifiedType();
|
ArgUnqualType = CanArg.getUnqualifiedType();
|
||||||
bool Success = (TDF & TDF_InOverloadResolution)?
|
bool Success =
|
||||||
S.isSameOrCompatibleFunctionType(ParamUnqualType,
|
(TDF & TDF_AllowCompatibleFunctionType)
|
||||||
ArgUnqualType) :
|
? S.isSameOrCompatibleFunctionType(ParamUnqualType, ArgUnqualType)
|
||||||
ParamUnqualType == ArgUnqualType;
|
: ParamUnqualType == ArgUnqualType;
|
||||||
if (Success)
|
if (Success)
|
||||||
return Sema::TDK_Success;
|
return Sema::TDK_Success;
|
||||||
}
|
}
|
||||||
|
@ -1524,17 +1529,56 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
|
||||||
return Sema::TDK_NonDeducedMismatch;
|
return Sema::TDK_NonDeducedMismatch;
|
||||||
|
|
||||||
// Check return types.
|
// Check return types.
|
||||||
if (Sema::TemplateDeductionResult Result =
|
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
|
||||||
DeduceTemplateArgumentsByTypeMatch(
|
S, TemplateParams, FunctionProtoParam->getReturnType(),
|
||||||
S, TemplateParams, FunctionProtoParam->getReturnType(),
|
FunctionProtoArg->getReturnType(), Info, Deduced, 0))
|
||||||
FunctionProtoArg->getReturnType(), Info, Deduced, 0))
|
|
||||||
return Result;
|
return Result;
|
||||||
|
|
||||||
return DeduceTemplateArguments(
|
// Check parameter types.
|
||||||
S, TemplateParams, FunctionProtoParam->param_type_begin(),
|
if (auto Result = DeduceTemplateArguments(
|
||||||
FunctionProtoParam->getNumParams(),
|
S, TemplateParams, FunctionProtoParam->param_type_begin(),
|
||||||
FunctionProtoArg->param_type_begin(),
|
FunctionProtoParam->getNumParams(),
|
||||||
FunctionProtoArg->getNumParams(), Info, Deduced, SubTDF);
|
FunctionProtoArg->param_type_begin(),
|
||||||
|
FunctionProtoArg->getNumParams(), Info, Deduced, SubTDF))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
if (TDF & TDF_AllowCompatibleFunctionType)
|
||||||
|
return Sema::TDK_Success;
|
||||||
|
|
||||||
|
// FIXME: Per core-2016/10/1019 (no corresponding core issue yet), permit
|
||||||
|
// deducing through the noexcept-specifier if it's part of the canonical
|
||||||
|
// type. libstdc++ relies on this.
|
||||||
|
Expr *NoexceptExpr = FunctionProtoParam->getNoexceptExpr();
|
||||||
|
if (NonTypeTemplateParmDecl *NTTP =
|
||||||
|
NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr)
|
||||||
|
: nullptr) {
|
||||||
|
assert(NTTP->getDepth() == Info.getDeducedDepth() &&
|
||||||
|
"saw non-type template parameter with wrong depth");
|
||||||
|
|
||||||
|
llvm::APSInt Noexcept(1);
|
||||||
|
switch (FunctionProtoArg->canThrow(S.Context)) {
|
||||||
|
case CT_Cannot:
|
||||||
|
Noexcept = 1;
|
||||||
|
LLVM_FALLTHROUGH;
|
||||||
|
|
||||||
|
case CT_Can:
|
||||||
|
// We give E in noexcept(E) the "deduced from array bound" treatment.
|
||||||
|
// FIXME: Should we?
|
||||||
|
return DeduceNonTypeTemplateArgument(
|
||||||
|
S, TemplateParams, NTTP, Noexcept, S.Context.BoolTy,
|
||||||
|
/*ArrayBound*/true, Info, Deduced);
|
||||||
|
|
||||||
|
case CT_Dependent:
|
||||||
|
if (Expr *ArgNoexceptExpr = FunctionProtoArg->getNoexceptExpr())
|
||||||
|
return DeduceNonTypeTemplateArgument(
|
||||||
|
S, TemplateParams, NTTP, ArgNoexceptExpr, Info, Deduced);
|
||||||
|
// Can't deduce anything from throw(T...).
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// FIXME: Detect non-deduced exception specification mismatches?
|
||||||
|
|
||||||
|
return Sema::TDK_Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Type::InjectedClassName: {
|
case Type::InjectedClassName: {
|
||||||
|
@ -1544,7 +1588,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
|
||||||
->getInjectedSpecializationType();
|
->getInjectedSpecializationType();
|
||||||
assert(isa<TemplateSpecializationType>(Param) &&
|
assert(isa<TemplateSpecializationType>(Param) &&
|
||||||
"injected class name is not a template specialization type");
|
"injected class name is not a template specialization type");
|
||||||
// fall through
|
LLVM_FALLTHROUGH;
|
||||||
}
|
}
|
||||||
|
|
||||||
// template-name<T> (where template-name refers to a class template)
|
// template-name<T> (where template-name refers to a class template)
|
||||||
|
@ -2820,6 +2864,17 @@ Sema::SubstituteExplicitTemplateArguments(
|
||||||
if (FunctionType) {
|
if (FunctionType) {
|
||||||
auto EPI = Proto->getExtProtoInfo();
|
auto EPI = Proto->getExtProtoInfo();
|
||||||
EPI.ExtParameterInfos = ExtParamInfos.getPointerOrNull(ParamTypes.size());
|
EPI.ExtParameterInfos = ExtParamInfos.getPointerOrNull(ParamTypes.size());
|
||||||
|
|
||||||
|
// In C++1z onwards, exception specifications are part of the function type,
|
||||||
|
// so substitution into the type must also substitute into the exception
|
||||||
|
// specification.
|
||||||
|
SmallVector<QualType, 4> ExceptionStorage;
|
||||||
|
if (getLangOpts().CPlusPlus1z &&
|
||||||
|
SubstExceptionSpec(
|
||||||
|
Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage,
|
||||||
|
MultiLevelTemplateArgumentList(*ExplicitArgumentList)))
|
||||||
|
return TDK_SubstitutionFailure;
|
||||||
|
|
||||||
*FunctionType = BuildFunctionType(ResultType, ParamTypes,
|
*FunctionType = BuildFunctionType(ResultType, ParamTypes,
|
||||||
Function->getLocation(),
|
Function->getLocation(),
|
||||||
Function->getDeclName(),
|
Function->getDeclName(),
|
||||||
|
@ -3714,13 +3769,6 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
|
||||||
= FunctionTemplate->getTemplateParameters();
|
= FunctionTemplate->getTemplateParameters();
|
||||||
QualType FunctionType = Function->getType();
|
QualType FunctionType = Function->getType();
|
||||||
|
|
||||||
// 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.
|
// Substitute any explicit template arguments.
|
||||||
LocalInstantiationScope InstScope(*this);
|
LocalInstantiationScope InstScope(*this);
|
||||||
SmallVector<DeducedTemplateArgument, 4> Deduced;
|
SmallVector<DeducedTemplateArgument, 4> Deduced;
|
||||||
|
@ -3737,6 +3785,13 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
|
||||||
NumExplicitlySpecified = Deduced.size();
|
NumExplicitlySpecified = Deduced.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When taking the address of a function, we require convertibility of
|
||||||
|
// the resulting function type. Otherwise, we allow arbitrary mismatches
|
||||||
|
// of calling convention and noreturn.
|
||||||
|
if (!IsAddressOfFunction)
|
||||||
|
ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType,
|
||||||
|
/*AdjustExceptionSpec*/false);
|
||||||
|
|
||||||
// Unevaluated SFINAE context.
|
// Unevaluated SFINAE context.
|
||||||
EnterExpressionEvaluationContext Unevaluated(
|
EnterExpressionEvaluationContext Unevaluated(
|
||||||
*this, Sema::ExpressionEvaluationContext::Unevaluated);
|
*this, Sema::ExpressionEvaluationContext::Unevaluated);
|
||||||
|
@ -3756,9 +3811,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ArgFunctionType.isNull()) {
|
if (!ArgFunctionType.isNull()) {
|
||||||
unsigned TDF = TDF_TopLevelParameterTypeList;
|
unsigned TDF =
|
||||||
if (IsAddressOfFunction)
|
TDF_TopLevelParameterTypeList | TDF_AllowCompatibleFunctionType;
|
||||||
TDF |= TDF_InOverloadResolution;
|
|
||||||
// Deduce template arguments from the function type.
|
// Deduce template arguments from the function type.
|
||||||
if (TemplateDeductionResult Result
|
if (TemplateDeductionResult Result
|
||||||
= DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
|
= DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
|
||||||
|
@ -3789,7 +3843,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
|
||||||
!ResolveExceptionSpec(Info.getLocation(), SpecializationFPT))
|
!ResolveExceptionSpec(Info.getLocation(), SpecializationFPT))
|
||||||
return TDK_MiscellaneousDeductionFailure;
|
return TDK_MiscellaneousDeductionFailure;
|
||||||
|
|
||||||
// Adjust the exception specification of the argument again to match the
|
// Adjust the exception specification of the argument to match the
|
||||||
// substituted and resolved type we just formed. (Calling convention and
|
// substituted and resolved type we just formed. (Calling convention and
|
||||||
// noreturn can't be dependent, so we don't actually need this for them
|
// noreturn can't be dependent, so we don't actually need this for them
|
||||||
// right now.)
|
// right now.)
|
||||||
|
@ -5127,6 +5181,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
|
||||||
for (unsigned I = 0, N = Proto->getNumParams(); I != N; ++I)
|
for (unsigned I = 0, N = Proto->getNumParams(); I != N; ++I)
|
||||||
MarkUsedTemplateParameters(Ctx, Proto->getParamType(I), OnlyDeduced,
|
MarkUsedTemplateParameters(Ctx, Proto->getParamType(I), OnlyDeduced,
|
||||||
Depth, Used);
|
Depth, Used);
|
||||||
|
if (auto *E = Proto->getNoexceptExpr())
|
||||||
|
MarkUsedTemplateParameters(Ctx, E, OnlyDeduced, Depth, Used);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1692,20 +1692,26 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
|
||||||
return TLB.getTypeSourceInfo(Context, Result);
|
return TLB.getTypeSourceInfo(Context, Result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sema::SubstExceptionSpec(SourceLocation Loc,
|
||||||
|
FunctionProtoType::ExceptionSpecInfo &ESI,
|
||||||
|
SmallVectorImpl<QualType> &ExceptionStorage,
|
||||||
|
const MultiLevelTemplateArgumentList &Args) {
|
||||||
|
assert(ESI.Type != EST_Uninstantiated);
|
||||||
|
|
||||||
|
bool Changed = false;
|
||||||
|
TemplateInstantiator Instantiator(*this, Args, Loc, DeclarationName());
|
||||||
|
return Instantiator.TransformExceptionSpec(Loc, ESI, ExceptionStorage,
|
||||||
|
Changed);
|
||||||
|
}
|
||||||
|
|
||||||
void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
|
void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto,
|
||||||
const MultiLevelTemplateArgumentList &Args) {
|
const MultiLevelTemplateArgumentList &Args) {
|
||||||
FunctionProtoType::ExceptionSpecInfo ESI =
|
FunctionProtoType::ExceptionSpecInfo ESI =
|
||||||
Proto->getExtProtoInfo().ExceptionSpec;
|
Proto->getExtProtoInfo().ExceptionSpec;
|
||||||
assert(ESI.Type != EST_Uninstantiated);
|
|
||||||
|
|
||||||
TemplateInstantiator Instantiator(*this, Args, New->getLocation(),
|
|
||||||
New->getDeclName());
|
|
||||||
|
|
||||||
SmallVector<QualType, 4> ExceptionStorage;
|
SmallVector<QualType, 4> ExceptionStorage;
|
||||||
bool Changed = false;
|
if (SubstExceptionSpec(New->getTypeSourceInfo()->getTypeLoc().getLocEnd(),
|
||||||
if (Instantiator.TransformExceptionSpec(
|
ESI, ExceptionStorage, Args))
|
||||||
New->getTypeSourceInfo()->getTypeLoc().getLocEnd(), ESI,
|
|
||||||
ExceptionStorage, Changed))
|
|
||||||
// On error, recover by dropping the exception specification.
|
// On error, recover by dropping the exception specification.
|
||||||
ESI.Type = EST_None;
|
ESI.Type = EST_None;
|
||||||
|
|
||||||
|
|
|
@ -192,7 +192,7 @@ namespace dr1330 { // dr1330: 4 c++11
|
||||||
static_assert(!noexcept(B<Q>().g()), "");
|
static_assert(!noexcept(B<Q>().g()), "");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename T> int f() throw(typename T::error) { return 0; } // expected-error 1-4{{prior to '::'}} expected-note 0-1{{instantiation of}}
|
template<typename T> int f() throw(typename T::error) { return 0; } // expected-error 1-4{{prior to '::'}} expected-note 0-1{{prior to '::'}} expected-note 0-1{{requested here}}
|
||||||
#if __cplusplus > 201402L
|
#if __cplusplus > 201402L
|
||||||
// expected-error@-2 0-1{{C++1z}} expected-note@-2 0-1{{noexcept}}
|
// expected-error@-2 0-1{{C++1z}} expected-note@-2 0-1{{noexcept}}
|
||||||
#endif
|
#endif
|
||||||
|
@ -203,7 +203,16 @@ namespace dr1330 { // dr1330: 4 c++11
|
||||||
decltype(f<char>()) f2; // expected-note {{instantiation of}}
|
decltype(f<char>()) f2; // expected-note {{instantiation of}}
|
||||||
bool f3 = noexcept(f<float>()); // expected-note {{instantiation of}}
|
bool f3 = noexcept(f<float>()); // expected-note {{instantiation of}}
|
||||||
#endif
|
#endif
|
||||||
template int f<short>(); // expected-note {{instantiation of}}
|
// In C++1z onwards, substituting explicit template arguments into the
|
||||||
|
// function type substitutes into the exception specification (because it's
|
||||||
|
// part of the type). In earlier languages, we don't notice there's a problem
|
||||||
|
// until we've already started to instantiate.
|
||||||
|
template int f<short>();
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
// expected-error@-2 {{does not refer to a function template}}
|
||||||
|
#else
|
||||||
|
// expected-note@-4 {{instantiation of}}
|
||||||
|
#endif
|
||||||
|
|
||||||
template<typename T> struct C {
|
template<typename T> struct C {
|
||||||
C() throw(typename T::type); // expected-error 1-2{{prior to '::'}}
|
C() throw(typename T::type); // expected-error 1-2{{prior to '::'}}
|
||||||
|
|
|
@ -46,10 +46,11 @@ namespace noexcept_conversion {
|
||||||
template <class T> int h(T *, T *); // expected-note {{deduced conflicting types for parameter 'T' ('void () noexcept' vs. 'void ()')}}
|
template <class T> int h(T *, T *); // expected-note {{deduced conflicting types for parameter 'T' ('void () noexcept' vs. 'void ()')}}
|
||||||
int x = h(g1, g2); // expected-error {{no matching function}}
|
int x = h(g1, g2); // expected-error {{no matching function}}
|
||||||
|
|
||||||
// FIXME: It seems like a defect that B is not deducible here.
|
// We consider it a defect that deduction does not support the following.
|
||||||
template<bool B> int i(void () noexcept(B)); // expected-note 2{{couldn't infer template argument 'B'}}
|
// FIXME: Check that the defect is resolved as we expect.
|
||||||
int i1 = i(g1); // expected-error {{no matching function}}
|
template<bool B> int i(void () noexcept(B));
|
||||||
int i2 = i(g2); // expected-error {{no matching function}}
|
int i1 = i(g1);
|
||||||
|
int i2 = i(g2);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// expected-no-diagnostics
|
// expected-no-diagnostics
|
||||||
|
|
|
@ -16,7 +16,7 @@ template<typename A, typename B> void redecl3() throw(B); // expected-error {{do
|
||||||
|
|
||||||
typedef int I;
|
typedef int I;
|
||||||
template<bool B> void redecl4(I) noexcept(B);
|
template<bool B> void redecl4(I) noexcept(B);
|
||||||
template<bool B> void redecl4(I) noexcept(B); // expected-note {{failed template argument deduction}}
|
template<bool B> void redecl4(I) noexcept(B); // expected-note {{could not match 'void (I) noexcept(false)' (aka 'void (int) noexcept(false)') against 'void (int) noexcept'}}
|
||||||
|
|
||||||
void (*init_with_exact_type_a)(int) noexcept = redecl4<true>;
|
void (*init_with_exact_type_a)(int) noexcept = redecl4<true>;
|
||||||
void (*init_with_mismatched_type_a)(int) = redecl4<true>;
|
void (*init_with_mismatched_type_a)(int) = redecl4<true>;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
|
||||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
|
||||||
|
|
||||||
template<typename T> class A; // expected-note 2 {{template parameter is declared here}} expected-note{{template is declared here}}
|
template<typename T> class A; // expected-note 2 {{template parameter is declared here}} expected-note{{template is declared here}}
|
||||||
|
|
||||||
|
@ -53,3 +54,56 @@ A1<Array<int, 17>::type> ax;
|
||||||
|
|
||||||
// FIXME: [temp.arg.type]p3. The check doesn't really belong here (it
|
// FIXME: [temp.arg.type]p3. The check doesn't really belong here (it
|
||||||
// belongs somewhere in the template instantiation section).
|
// belongs somewhere in the template instantiation section).
|
||||||
|
|
||||||
|
#if __cplusplus >= 201703
|
||||||
|
// As a defect resolution, we support deducing B in noexcept(B).
|
||||||
|
namespace deduce_noexcept {
|
||||||
|
template<typename> struct function;
|
||||||
|
template<typename R, typename ...A, bool N>
|
||||||
|
struct function<R(A...) noexcept(N)> {
|
||||||
|
static constexpr bool Noexcept = N;
|
||||||
|
};
|
||||||
|
static_assert(function<int(float, double) noexcept>::Noexcept);
|
||||||
|
static_assert(!function<int(float, double)>::Noexcept);
|
||||||
|
|
||||||
|
void noexcept_function() noexcept;
|
||||||
|
void throwing_function();
|
||||||
|
|
||||||
|
template<typename T, bool B> float &deduce_function(T(*)() noexcept(B)); // expected-note {{candidate}}
|
||||||
|
template<typename T> int &deduce_function(T(*)() noexcept); // expected-note {{candidate}}
|
||||||
|
void test_function_deduction() {
|
||||||
|
// FIXME: This should probably unambiguously select the second overload.
|
||||||
|
int &r = deduce_function(noexcept_function); // expected-error {{ambiguous}}
|
||||||
|
float &s = deduce_function(throwing_function);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace low_priority_deduction {
|
||||||
|
template<int> struct A {};
|
||||||
|
template<auto B> void f(A<B>, void(*)() noexcept(B)) {
|
||||||
|
using T = decltype(B);
|
||||||
|
using T = int;
|
||||||
|
}
|
||||||
|
void g() { f(A<0>(), g); } // ok, deduce B as an int
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: It's not clear whether this should work. We're told to deduce with
|
||||||
|
// P being the function template type and A being the declared type, which
|
||||||
|
// would accept this, but considering the exception specification in such
|
||||||
|
// cases breaks new/delete matching.
|
||||||
|
template<bool Noexcept> void dep() noexcept(Noexcept) {} // expected-note 3{{couldn't infer template argument 'Noexcept'}}
|
||||||
|
template void dep(); // expected-error {{does not refer to a function template}}
|
||||||
|
template void dep() noexcept(true); // expected-error {{does not refer to a function template}}
|
||||||
|
template void dep() noexcept(false); // expected-error {{does not refer to a function template}}
|
||||||
|
|
||||||
|
// FIXME: It's also not clear whether this should be valid: do we substitute
|
||||||
|
// into the function type (including the exception specification) or not?
|
||||||
|
template<typename T> typename T::type1 f() noexcept(T::a);
|
||||||
|
template<typename T> typename T::type2 f() noexcept(T::b) {}
|
||||||
|
struct X {
|
||||||
|
static constexpr bool b = true;
|
||||||
|
using type1 = void;
|
||||||
|
using type2 = void;
|
||||||
|
};
|
||||||
|
template void f<X>();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue