Skip to content

Commit be2381c

Browse files
committed
[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 #66153 (comment) 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,
1 parent 7d1a9e8 commit be2381c

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
@@ -444,6 +444,8 @@ Improvements to Clang's diagnostics
444444
- ``-Wzero-as-null-pointer-constant`` diagnostic is no longer emitted when using ``__null``
445445
(or, more commonly, ``NULL`` when the platform defines it as ``__null``) to be more consistent
446446
with GCC.
447+
- Clang will warn on deprecated specializations used in system headers when their instantiation
448+
is caused by user code.
447449

448450
Improvements to Clang's time-trace
449451
----------------------------------

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 (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)