Skip to content

Commit

Permalink
[Clang] Warn on deprecated specializations used in system headers. (#…
Browse files Browse the repository at this point in the history
…70353)

When the top of the instantiation stack is in user code.

The 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
#66153 (comment)
as Clang never emitted the libc++ warnings.

Because Clang likes to eagerly instantiate, we can 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 instructing the diag
engine not to silence warning in system headers.
  • Loading branch information
cor3ntin committed Nov 17, 2023
1 parent 764c3af commit aafad2d
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 0 deletions.
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,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
----------------------------------
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -8464,6 +8464,8 @@ class Sema final {
ArrayRef<TemplateArgument> SugaredConverted,
ArrayRef<TemplateArgument> CanonicalConverted, bool &HasDefaultArg);

SourceLocation getTopMostPointOfInstantiation(const NamedDecl *) const;

/// Specifies the context in which a particular template
/// argument is being checked.
enum CheckTemplateArgumentKind {
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/Sema/SemaAvailability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
22 changes: 22 additions & 0 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<FunctionDecl>(N)) {
if (!FD->isFunctionTemplateSpecialization())
return FD->getLocation();
} else if (!isa<ClassTemplateSpecializationDecl,
VarTemplateSpecializationDecl>(N)) {
return N->getLocation();
}
for (const CodeSynthesisContext &CSC : CodeSynthesisContexts) {
if (!CSC.isInstantiationRecord() || CSC.PointOfInstantiation.isInvalid())
continue;
return CSC.PointOfInstantiation;
}
return N->getLocation();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s

#ifdef BE_THE_HEADER
#pragma clang system_header

template <typename T>
struct traits;

template <>
struct [[deprecated]] traits<int> {}; // expected-note {{'traits<int>' has been explicitly marked deprecated here}}

template<typename T, typename Trait = traits<T>> // expected-warning {{'traits<int>' is deprecated}}
struct basic_string {};

// should not warn, defined and used in system headers
using __do_what_i_say_not_what_i_do = traits<int> ;

template<typename T, typename Trait = traits<double>>
struct should_not_warn {};

#else
#define BE_THE_HEADER
#include __FILE__

basic_string<int> test1; // expected-note {{in instantiation of default argument for 'basic_string<int>' required here}}
should_not_warn<int> test2;

#endif

0 comments on commit aafad2d

Please sign in to comment.