-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Clang] Warn on deprecated specializations used in system headers. #70353
[Clang] Warn on deprecated specializations used in system headers. #70353
Conversation
@llvm/pr-subscribers-clang Author: cor3ntin (cor3ntin) ChangesWhen 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 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. Full diff: https://github.com/llvm/llvm-project/pull/70353.diff 5 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7238386231e1a28..0c46e0a5912905e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -404,6 +404,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.
Bug Fixes in This Version
-------------------------
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 18ac85011aa752a..1a75fff331add5a 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8476,6 +8476,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 {
diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp
index 84c06566387ccbe..846a31a79673096 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 c2477ec0063e418..61d034e13b0a292 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -11615,3 +11615,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<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();
+}
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 000000000000000..270e4292bf9a47b
--- /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 <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
|
I like this very much so long as it doesn't turn out to be too noisy! |
@cor3ntin This is really nice, thanks for the patch! The CI should pass if you merge |
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 llvm#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,
d763ea8
to
be2381c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
clang/lib/Sema/SemaTemplate.cpp
Outdated
SourceLocation Sema::getTopMostPointOfInstantiation(const NamedDecl *N) const { | ||
if (!getLangOpts().CPlusPlus || CodeSynthesisContexts.empty()) | ||
return N->getLocation(); | ||
if (auto *FD = dyn_cast<FunctionDecl>(N)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (auto *FD = dyn_cast<FunctionDecl>(N)) { | |
if (const auto *FD = dyn_cast<FunctionDecl>(N)) { |
struct traits; | ||
|
||
template <> | ||
struct [[ deprecated]] traits<int> {}; // expected-note {{'traits<int>' has been explicitly marked deprecated here}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
struct [[ deprecated]] traits<int> {}; // expected-note {{'traits<int>' has been explicitly marked deprecated here}} | |
struct [[deprecated]] traits<int> {}; // expected-note {{'traits<int>' has been explicitly marked deprecated here}} |
…lvm#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.
…lvm#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.
This patch has quite a bit of history. First, it must be noted that the Standard only specifies specializations of char_traits for char, char8_t, char16_t, char32_t and wchar_t. However, before this patch, we would provide a base template that accepted anything, and as a result code like `std::basic_string<long long>` would compile but nobody knows what it really does. It basically compiles by accident. We marked the base template as deprecated in LLVM 15 or 16 and were planning on removing it in LLVM 17, which we did in e30a148. However, it turned out that the deprecation warning had never been visible in user code since Clang did not surface that warning from system headers. As a result, this caught people by surprise and we decided to reintroduce the base template in LLVM 17 in cce062d. Since then, llvm#70353 changed Clang so that such deprecation warnings would be visible from user code. Hence, this patch closes the loop and removes the deprecated specializations. TODO: This will be landed in the LLVM 19 time frame, not before. TODO: This patch also needs to update the release notes for LLVM 19 once we have some.
This patch exposes the use of deprecated specializations in the third-party Google Test suite built via this buildbot https://lab.llvm.org/staging/#/builders/104/builds/106/steps/6/logs/stdio. The bot ordinality isn't in staging, it is there temporary while we test and update its configuration and intend to move it back to the main server once it builds libcxx and libcxxabi cleanly. Can you provide any insight on how to resolve these warning? Would specifying |
I'm not familiar with your exact setup, but I think you should probably report those warnings to Google Test and turn off deprecation warnings in your build with |
This change fixes a build break introduced by aafad2d(#70353) on the clang-ppc64le-rhel build bot. If the third-party Google Test suite is built using gcc-toolset-12, the implementation of std::stable_sort in the toolchain will use a get_temporary_buffer declaration that is marked _GLIBCXX17_DEPRECATED. This change adds -Wno-deprecated-declarations to the GTest flags if the toolchain is detected in the build compiler on linux.
These test cases fail when the libcxx and libcxxabi runtimes are built on Linux PowerPC. XFailing them until the issue is resolved.
This patch has quite a bit of history. First, it must be noted that the Standard only specifies specializations of char_traits for char, char8_t, char16_t, char32_t and wchar_t. However, before this patch, we would provide a base template that accepted anything, and as a result code like `std::basic_string<long long>` would compile but nobody knows what it really does. It basically compiles by accident. We marked the base template as deprecated in LLVM 15 or 16 and were planning on removing it in LLVM 17, which we did in e30a148. However, it turned out that the deprecation warning had never been visible in user code since Clang did not surface that warning from system headers. As a result, this caught people by surprise and we decided to reintroduce the base template in LLVM 17 in cce062d. Since then, llvm#70353 changed Clang so that such deprecation warnings would be visible from user code. Hence, this patch closes the loop and removes the deprecated specializations.
This patch has quite a bit of history. First, it must be noted that the Standard only specifies specializations of char_traits for char, char8_t, char16_t, char32_t and wchar_t. However, before this patch, we would provide a base template that accepted anything, and as a result code like `std::basic_string<long long>` would compile but nobody knows what it really does. It basically compiles by accident. We marked the base template as deprecated in LLVM 15 or 16 and were planning on removing it in LLVM 17, which we did in e30a148. However, it turned out that the deprecation warning had never been visible in user code since Clang did not surface that warning from system headers. As a result, this caught people by surprise and we decided to reintroduce the base template in LLVM 17 in cce062d. Since then, #70353 changed Clang so that such deprecation warnings would be visible from user code. Hence, this patch closes the loop and removes the deprecated specializations.
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.