Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -6991,6 +6991,13 @@ ObjCLifetimeConversion)) RefExpr = ImpCastExprToType(RefExpr.get(), ParamType.getUnqualifiedType(), CK_NoOp); + // Starting with C++17 the noexcept is part of the function signature but + // a noexcept function can be converted to a noexcept(false) function. + QualType ResultTy; + if (IsFunctionConversion(((Expr *)RefExpr.get())->getType(), + ParamType.getUnqualifiedType(), ResultTy)) + RefExpr = ImpCastExprToType(RefExpr.get(), ResultTy, CK_NoOp); + assert(!RefExpr.isInvalid() && Context.hasSameType(((Expr*) RefExpr.get())->getType(), ParamType.getUnqualifiedType())); Index: clang/test/CXX/conv/conv.fctptr/template-noexcept.cpp =================================================================== --- /dev/null +++ clang/test/CXX/conv/conv.fctptr/template-noexcept.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++2a -fsyntax-only -verify %s + +// Starting with C++17 the noexcept is part of the function signature but +// a noexcept function can be converted to a noexcept(false) function. +// The tests were added for PR40024. + +#if __cplusplus < 201703L +// expected-no-diagnostics +#endif + +namespace valid_conversion { +struct S { + int f(void) noexcept { return 110; } +} s; + +template +int f10(void) { return (s.*a)(); } + +int foo(void) { + return f10<&S::f>(); +} +} // namespace valid_conversion + +namespace invalid_conversion { +struct S { + int f(void) { return 110; } +} s; + +#if __cplusplus >= 201703L +// expected-note@+3 {{candidate template ignored: invalid explicitly-specified argument for template parameter 'a'}} +#endif +template +int f10(void) { return (s.*a)(); } + +#if __cplusplus >= 201703L +// expected-error@+3 {{no matching function for call to 'f10'}} +#endif +int foo(void) { + return f10<&S::f>(); +} +} // namespace invalid_conversion Index: clang/test/CXX/conv/conv.fctptr/template-noreturn.cpp =================================================================== --- /dev/null +++ clang/test/CXX/conv/conv.fctptr/template-noreturn.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++2a -fsyntax-only -verify %s + +typedef int (*fp)(); +typedef int (*fpnr)() __attribute__((noreturn)); +#if __cplusplus < 201703L +// expected-note@+2 {{template parameter is declared here}} +#endif +template +struct FP {}; + +#if __cplusplus < 201703L +// expected-note@+2 {{template parameter is declared here}} +#endif +template +struct FPNR {}; + +int f(); +int fnr() __attribute__((noreturn)); + +FP<&f> fp_valid; +FPNR<&fnr> fpnr_valid; + +#if __cplusplus < 201703L +// expected-error@+2 {{non-type template argument of type 'int (*)() __attribute__((noreturn))' cannot be converted to a value of type 'fp' (aka 'int (*)()')}} +#endif +FP<&fnr> fp_invalid_before_cxx17; + +#if __cplusplus < 201703L +// expected-error@+4 {{non-type template argument of type 'int (*)()' cannot be converted to a value of type 'fpnr' (aka 'int (*)() __attribute__((noreturn))')}} +#else +// expected-error@+2 {{value of type 'int (*)()' is not implicitly convertible to 'fpnr' (aka 'int (*)() __attribute__((noreturn))')}} +#endif +FPNR<&f> fpnr_invalid;