Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -9914,6 +9914,28 @@ OldDecl, MergeTypeWithPrevious, Previous); } +/// Returns true if the type T is a function type that contains a noexcept specifier. +/// This check recursively checks the params and return types of T if T happens +/// to be a function. +static bool hasNoexcept(QualType T) { + // Strip off declarator chunks that could be between us and a function + // type. We don't need to look far, exception specifications are very + // restricted prior to C++17. + if (auto *RT = T->getAs()) + T = RT->getPointeeType(); + else if (T->isAnyPointerType()) + T = T->getPointeeType(); + else if (auto *MPT = T->getAs()) + T = MPT->getPointeeType(); + if (auto *FPT = T->getAs()) { + if (FPT->isNothrow() || hasNoexcept(FPT->getReturnType()) || + llvm::any_of(FPT->param_types(), + [](QualType Q) { return hasNoexcept(Q); })) + return true; + } + return false; +} + /// Perform semantic checking of a new function declaration. /// /// Performs semantic analysis of the new function declaration @@ -10240,30 +10262,14 @@ // most cases, and exception specifications are not permitted in most other // contexts where they could make it into a mangling.) if (!getLangOpts().CPlusPlus17 && !NewFD->getPrimaryTemplate()) { - auto HasNoexcept = [&](QualType T) -> bool { - // Strip off declarator chunks that could be between us and a function - // type. We don't need to look far, exception specifications are very - // restricted prior to C++17. - if (auto *RT = T->getAs()) - T = RT->getPointeeType(); - else if (T->isAnyPointerType()) - T = T->getPointeeType(); - else if (auto *MPT = T->getAs()) - T = MPT->getPointeeType(); - if (auto *FPT = T->getAs()) - if (FPT->isNothrow()) - return true; - return false; - }; - auto *FPT = NewFD->getType()->castAs(); - bool AnyNoexcept = HasNoexcept(FPT->getReturnType()); - for (QualType T : FPT->param_types()) - AnyNoexcept |= HasNoexcept(T); - if (AnyNoexcept) + if (hasNoexcept(FPT->getReturnType()) || + llvm::any_of(FPT->param_types(), + [](QualType Q) { return hasNoexcept(Q); })) { Diag(NewFD->getLocation(), diag::warn_cxx17_compat_exception_spec_in_signature) << NewFD; + } } if (!Redeclaration && LangOpts.CUDA) Index: test/CXX/except/except.spec/p2-places.cpp =================================================================== --- test/CXX/except/except.spec/p2-places.cpp +++ test/CXX/except/except.spec/p2-places.cpp @@ -55,7 +55,7 @@ void (*h())() noexcept(false); - void (*i() noexcept(false))(void (*)() noexcept(true)) noexcept(false); + void (*i() noexcept(false))(void (*)() noexcept(true)) noexcept(false); // expected-warning {{mangled name of 'i' will change in C++17 due to non-throwing exception specification in function signature}} void (**k)(void pfa() noexcept(false)); // no-error Index: test/SemaCXX/cxx1z-noexcept-function-type.cpp =================================================================== --- test/SemaCXX/cxx1z-noexcept-function-type.cpp +++ test/SemaCXX/cxx1z-noexcept-function-type.cpp @@ -83,14 +83,18 @@ auto f5() -> void (*)() throw(); auto f6() -> void (&)() throw(); auto f7() -> void (X::*)() throw(); + void f8(int, void (*)(int, void (*)() noexcept)); + void f9(void (*g())() noexcept); #if __cplusplus <= 201402L && !defined(NO_COMPAT_MANGLING) - // expected-warning@-8 {{mangled name of 'f1' will change in C++17 due to non-throwing exception specification in function signature}} - // expected-warning@-8 {{mangled name of 'f2' will change in C++17 due to non-throwing exception specification in function signature}} - // expected-warning@-8 {{mangled name of 'f3' will change in C++17 due to non-throwing exception specification in function signature}} - // expected-warning@-8 {{mangled name of 'f4' will change in C++17 due to non-throwing exception specification in function signature}} - // expected-warning@-8 {{mangled name of 'f5' will change in C++17 due to non-throwing exception specification in function signature}} - // expected-warning@-8 {{mangled name of 'f6' will change in C++17 due to non-throwing exception specification in function signature}} - // expected-warning@-8 {{mangled name of 'f7' will change in C++17 due to non-throwing exception specification in function signature}} + // expected-warning@-10 {{mangled name of 'f1' will change in C++17 due to non-throwing exception specification in function signature}} + // expected-warning@-10 {{mangled name of 'f2' will change in C++17 due to non-throwing exception specification in function signature}} + // expected-warning@-10 {{mangled name of 'f3' will change in C++17 due to non-throwing exception specification in function signature}} + // expected-warning@-10 {{mangled name of 'f4' will change in C++17 due to non-throwing exception specification in function signature}} + // expected-warning@-10 {{mangled name of 'f5' will change in C++17 due to non-throwing exception specification in function signature}} + // expected-warning@-10 {{mangled name of 'f6' will change in C++17 due to non-throwing exception specification in function signature}} + // expected-warning@-10 {{mangled name of 'f7' will change in C++17 due to non-throwing exception specification in function signature}} + // expected-warning@-10 {{mangled name of 'f8' will change in C++17 due to non-throwing exception specification in function signature}} + // expected-warning@-10 {{mangled name of 'f9' will change in C++17 due to non-throwing exception specification in function signature}} #endif // An instantiation-dependent exception specification needs to be mangled in