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..c188dd34014a4 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 (const 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..79c9d339b6f20 --- /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