Skip to content

Commit fe53a03

Browse files
cor3ntinzahiraam
authored andcommitted
[Clang] Warn on deprecated specializations used in system headers. (llvm#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 llvm#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.
1 parent 9d30831 commit fe53a03

File tree

5 files changed

+77
-0
lines changed

5 files changed

+77
-0
lines changed

Diff for: clang/docs/ReleaseNotes.rst

+2
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,8 @@ Improvements to Clang's diagnostics
459459
- ``-Wzero-as-null-pointer-constant`` diagnostic is no longer emitted when using ``__null``
460460
(or, more commonly, ``NULL`` when the platform defines it as ``__null``) to be more consistent
461461
with GCC.
462+
- Clang will warn on deprecated specializations used in system headers when their instantiation
463+
is caused by user code.
462464

463465
Improvements to Clang's time-trace
464466
----------------------------------

Diff for: clang/include/clang/Sema/Sema.h

+2
Original file line numberDiff line numberDiff line change
@@ -8464,6 +8464,8 @@ class Sema final {
84648464
ArrayRef<TemplateArgument> SugaredConverted,
84658465
ArrayRef<TemplateArgument> CanonicalConverted, bool &HasDefaultArg);
84668466

8467+
SourceLocation getTopMostPointOfInstantiation(const NamedDecl *) const;
8468+
84678469
/// Specifies the context in which a particular template
84688470
/// argument is being checked.
84698471
enum CheckTemplateArgumentKind {

Diff for: clang/lib/Sema/SemaAvailability.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,29 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
536536
}
537537
}
538538

539+
// We emit deprecation warning for deprecated specializations
540+
// when their instantiation stacks originate outside
541+
// of a system header, even if the diagnostics is suppresed at the
542+
// point of definition.
543+
SourceLocation InstantiationLoc =
544+
S.getTopMostPointOfInstantiation(ReferringDecl);
545+
bool ShouldAllowWarningInSystemHeader =
546+
InstantiationLoc != Loc &&
547+
!S.getSourceManager().isInSystemHeader(InstantiationLoc);
548+
struct AllowWarningInSystemHeaders {
549+
AllowWarningInSystemHeaders(DiagnosticsEngine &E,
550+
bool AllowWarningInSystemHeaders)
551+
: Engine(E), Prev(E.getSuppressSystemWarnings()) {
552+
E.setSuppressSystemWarnings(!AllowWarningInSystemHeaders);
553+
}
554+
~AllowWarningInSystemHeaders() { Engine.setSuppressSystemWarnings(Prev); }
555+
556+
private:
557+
DiagnosticsEngine &Engine;
558+
bool Prev;
559+
} SystemWarningOverrideRAII(S.getDiagnostics(),
560+
ShouldAllowWarningInSystemHeader);
561+
539562
if (!Message.empty()) {
540563
S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts;
541564
if (ObjCProperty)

Diff for: clang/lib/Sema/SemaTemplate.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -11601,3 +11601,25 @@ void Sema::checkSpecializationReachability(SourceLocation Loc,
1160111601
Sema::AcceptableKind::Reachable)
1160211602
.check(Spec);
1160311603
}
11604+
11605+
/// Returns the top most location responsible for the definition of \p N.
11606+
/// If \p N is a a template specialization, this is the location
11607+
/// of the top of the instantiation stack.
11608+
/// Otherwise, the location of \p N is returned.
11609+
SourceLocation Sema::getTopMostPointOfInstantiation(const NamedDecl *N) const {
11610+
if (!getLangOpts().CPlusPlus || CodeSynthesisContexts.empty())
11611+
return N->getLocation();
11612+
if (const auto *FD = dyn_cast<FunctionDecl>(N)) {
11613+
if (!FD->isFunctionTemplateSpecialization())
11614+
return FD->getLocation();
11615+
} else if (!isa<ClassTemplateSpecializationDecl,
11616+
VarTemplateSpecializationDecl>(N)) {
11617+
return N->getLocation();
11618+
}
11619+
for (const CodeSynthesisContext &CSC : CodeSynthesisContexts) {
11620+
if (!CSC.isInstantiationRecord() || CSC.PointOfInstantiation.isInvalid())
11621+
continue;
11622+
return CSC.PointOfInstantiation;
11623+
}
11624+
return N->getLocation();
11625+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
#ifdef BE_THE_HEADER
4+
#pragma clang system_header
5+
6+
template <typename T>
7+
struct traits;
8+
9+
template <>
10+
struct [[deprecated]] traits<int> {}; // expected-note {{'traits<int>' has been explicitly marked deprecated here}}
11+
12+
template<typename T, typename Trait = traits<T>> // expected-warning {{'traits<int>' is deprecated}}
13+
struct basic_string {};
14+
15+
// should not warn, defined and used in system headers
16+
using __do_what_i_say_not_what_i_do = traits<int> ;
17+
18+
template<typename T, typename Trait = traits<double>>
19+
struct should_not_warn {};
20+
21+
#else
22+
#define BE_THE_HEADER
23+
#include __FILE__
24+
25+
basic_string<int> test1; // expected-note {{in instantiation of default argument for 'basic_string<int>' required here}}
26+
should_not_warn<int> test2;
27+
28+
#endif

0 commit comments

Comments
 (0)