From be2381c9e795af6dc6eec9a3eb9a0ef467edfe5c Mon Sep 17 00:00:00 2001 From: Corentin Jabot Date: Thu, 26 Oct 2023 18:40:15 +0200 Subject: [PATCH 1/2] [Clang] Warn on deprecated specializations used in system headers. When the top of the instantiation stack is in user code. Thge goal of this PR is to allow deprecation of some char_traits specializations in libc++ as done in https://reviews.llvm.org/D157058 which was later reverted by https://github.com/llvm/llvm-project/pull/66153#issuecomment-1719578384 As Clang never emitted the libc++ warnings. Because Clang likes to eagerly instantiate, we look for the location of the top of the instantiation stack, and emit a warning if that location is in user code. The warning emission is forced by temporarily instruct the diag engine not to silence warning in system headers, --- clang/docs/ReleaseNotes.rst | 2 ++ clang/include/clang/Sema/Sema.h | 2 ++ clang/lib/Sema/SemaAvailability.cpp | 23 +++++++++++++++ clang/lib/Sema/SemaTemplate.cpp | 22 +++++++++++++++ ...ated-specializations-in-system-headers.cpp | 28 +++++++++++++++++++ 5 files changed, 77 insertions(+) create mode 100644 clang/test/SemaCXX/warn-deprecated-specializations-in-system-headers.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 08ffb08e341ab..79534687139cc 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -444,6 +444,8 @@ Improvements to Clang's diagnostics - ``-Wzero-as-null-pointer-constant`` diagnostic is no longer emitted when using ``__null`` (or, more commonly, ``NULL`` when the platform defines it as ``__null``) to be more consistent with GCC. +- Clang will warn on deprecated specializations used in system headers when their instantiation + is caused by user code. Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 501dc01200a1c..73981a4d657d4 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8464,6 +8464,8 @@ class Sema final { ArrayRef SugaredConverted, ArrayRef CanonicalConverted, bool &HasDefaultArg); + SourceLocation getTopMostPointOfInstantiation(const NamedDecl *) const; + /// Specifies the context in which a particular template /// argument is being checked. enum CheckTemplateArgumentKind { diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index 84c06566387cc..846a31a796730 100644 --- a/clang/lib/Sema/SemaAvailability.cpp +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -536,6 +536,29 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, } } + // We emit deprecation warning for deprecated specializations + // when their instantiation stacks originate outside + // of a system header, even if the diagnostics is suppresed at the + // point of definition. + SourceLocation InstantiationLoc = + S.getTopMostPointOfInstantiation(ReferringDecl); + bool ShouldAllowWarningInSystemHeader = + InstantiationLoc != Loc && + !S.getSourceManager().isInSystemHeader(InstantiationLoc); + struct AllowWarningInSystemHeaders { + AllowWarningInSystemHeaders(DiagnosticsEngine &E, + bool AllowWarningInSystemHeaders) + : Engine(E), Prev(E.getSuppressSystemWarnings()) { + E.setSuppressSystemWarnings(!AllowWarningInSystemHeaders); + } + ~AllowWarningInSystemHeaders() { Engine.setSuppressSystemWarnings(Prev); } + + private: + DiagnosticsEngine &Engine; + bool Prev; + } SystemWarningOverrideRAII(S.getDiagnostics(), + ShouldAllowWarningInSystemHeader); + if (!Message.empty()) { S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts; if (ObjCProperty) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 766ebd90fded0..cbf63172a1e30 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -11601,3 +11601,25 @@ void Sema::checkSpecializationReachability(SourceLocation Loc, Sema::AcceptableKind::Reachable) .check(Spec); } + +/// Returns the top most location responsible for the definition of \p N. +/// If \p N is a a template specialization, this is the location +/// of the top of the instantiation stack. +/// Otherwise, the location of \p N is returned. +SourceLocation Sema::getTopMostPointOfInstantiation(const NamedDecl *N) const { + if (!getLangOpts().CPlusPlus || CodeSynthesisContexts.empty()) + return N->getLocation(); + if (auto *FD = dyn_cast(N)) { + if (!FD->isFunctionTemplateSpecialization()) + return FD->getLocation(); + } else if (!isa(N)) { + return N->getLocation(); + } + for (const CodeSynthesisContext &CSC : CodeSynthesisContexts) { + if (!CSC.isInstantiationRecord() || CSC.PointOfInstantiation.isInvalid()) + continue; + return CSC.PointOfInstantiation; + } + return N->getLocation(); +} diff --git a/clang/test/SemaCXX/warn-deprecated-specializations-in-system-headers.cpp b/clang/test/SemaCXX/warn-deprecated-specializations-in-system-headers.cpp new file mode 100644 index 0000000000000..270e4292bf9a4 --- /dev/null +++ b/clang/test/SemaCXX/warn-deprecated-specializations-in-system-headers.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +#ifdef BE_THE_HEADER +#pragma clang system_header + +template +struct traits; + +template <> +struct [[ deprecated]] traits {}; // expected-note {{'traits' has been explicitly marked deprecated here}} + +template> // expected-warning {{'traits' is deprecated}} +struct basic_string {}; + +// should not warn, defined and used in system headers +using __do_what_i_say_not_what_i_do = traits ; + +template> +struct should_not_warn {}; + +#else +#define BE_THE_HEADER +#include __FILE__ + +basic_string test1; // expected-note {{in instantiation of default argument for 'basic_string' required here}} +should_not_warn test2; + +#endif From 5a43d23957e0672f1207e7002f8eef71f67a9fec Mon Sep 17 00:00:00 2001 From: Corentin Jabot Date: Fri, 17 Nov 2023 16:40:52 +0100 Subject: [PATCH 2/2] Address Aaron's feedback --- clang/lib/Sema/SemaTemplate.cpp | 2 +- .../warn-deprecated-specializations-in-system-headers.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index cbf63172a1e30..c188dd34014a4 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -11609,7 +11609,7 @@ void Sema::checkSpecializationReachability(SourceLocation Loc, SourceLocation Sema::getTopMostPointOfInstantiation(const NamedDecl *N) const { if (!getLangOpts().CPlusPlus || CodeSynthesisContexts.empty()) return N->getLocation(); - if (auto *FD = dyn_cast(N)) { + if (const auto *FD = dyn_cast(N)) { if (!FD->isFunctionTemplateSpecialization()) return FD->getLocation(); } else if (!isa struct traits; template <> -struct [[ deprecated]] traits {}; // expected-note {{'traits' has been explicitly marked deprecated here}} +struct [[deprecated]] traits {}; // expected-note {{'traits' has been explicitly marked deprecated here}} template> // expected-warning {{'traits' is deprecated}} struct basic_string {};