[clang] Avoid inheriting [[noreturn]] in explicit function template specializations (#150003)
This patch fixes incorrect behavior in Clang where [[noreturn]] (either spelled or inferred) was being inherited by explicit specializations of function templates or member function templates, even when those specializations returned normally. Follow up on https://github.com/llvm/llvm-project/pull/145166 (cherry picked from commit 22fef005225b129d73ade4ed995fc0ec0c7be044)
This commit is contained in:
parent
8d38ccbb5a
commit
087cb2e91c
@ -3267,6 +3267,14 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
|
||||
if (isa<UsedAttr>(I) || isa<RetainAttr>(I))
|
||||
continue;
|
||||
|
||||
if (isa<InferredNoReturnAttr>(I)) {
|
||||
if (auto *FD = dyn_cast<FunctionDecl>(New)) {
|
||||
if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
|
||||
continue; // Don't propagate inferred noreturn attributes to explicit
|
||||
// specializations.
|
||||
}
|
||||
}
|
||||
|
||||
if (mergeDeclAttribute(*this, New, I, LocalAMK))
|
||||
foundAny = true;
|
||||
}
|
||||
|
@ -1970,6 +1970,13 @@ void clang::inferNoReturnAttr(Sema &S, const Decl *D) {
|
||||
if (!FD)
|
||||
return;
|
||||
|
||||
// Skip explicit specializations here as they may have
|
||||
// a user-provided definition that may deliberately differ from the primary
|
||||
// template. If an explicit specialization truly never returns, the user
|
||||
// should explicitly mark it with [[noreturn]].
|
||||
if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
|
||||
return;
|
||||
|
||||
auto *NonConstFD = const_cast<FunctionDecl *>(FD);
|
||||
DiagnosticsEngine &Diags = S.getDiagnostics();
|
||||
if (Diags.isIgnored(diag::warn_falloff_nonvoid, FD->getLocation()) &&
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -fexceptions -Wreturn-type -verify %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -fexceptions -Wreturn-type -Winvalid-noreturn -verify %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
namespace std {
|
||||
@ -44,3 +44,22 @@ void testTemplates() {
|
||||
throwErrorTemplate("ERROR");
|
||||
(void)ensureZeroTemplate(42);
|
||||
}
|
||||
|
||||
// Ensure that explicit specialization of a member function does not inherit
|
||||
// the warning from the primary template.
|
||||
|
||||
template<typename T>
|
||||
struct S {
|
||||
void f();
|
||||
void g();
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void S<T>::f() { throw 0; }
|
||||
template<>
|
||||
void S<int>::f() {}
|
||||
|
||||
template<typename T>
|
||||
void S<T>::g() {}
|
||||
template<>
|
||||
void S<int>::g() { throw 0; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user