Skip to content
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

Merged
merged 2 commits into from
Nov 17, 2023

Conversation

cor3ntin
Copy link
Contributor

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.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Oct 26, 2023
@cor3ntin
Copy link
Contributor Author

@ldionne @mordante Ping for visibility :)

@llvmbot
Copy link
Collaborator

llvmbot commented Oct 26, 2023

@llvm/pr-subscribers-clang

Author: cor3ntin (cor3ntin)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/70353.diff

5 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+2)
  • (modified) clang/include/clang/Sema/Sema.h (+2)
  • (modified) clang/lib/Sema/SemaAvailability.cpp (+23)
  • (modified) clang/lib/Sema/SemaTemplate.cpp (+22)
  • (added) clang/test/SemaCXX/warn-deprecated-specializations-in-system-headers.cpp (+28)
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

@tahonermann
Copy link
Contributor

I like this very much so long as it doesn't turn out to be too noisy!

@ldionne
Copy link
Member

ldionne commented Oct 31, 2023

@cor3ntin This is really nice, thanks for the patch! The CI should pass if you merge main into your branch -- you were the victim of a temporary CI issue that has been fixed since then.

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,
@cor3ntin cor3ntin force-pushed the corentin/deprecate_system_headers branch from d763ea8 to be2381c Compare November 17, 2023 15:37
Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

SourceLocation Sema::getTopMostPointOfInstantiation(const NamedDecl *N) const {
if (!getLangOpts().CPlusPlus || CodeSynthesisContexts.empty())
return N->getLocation();
if (auto *FD = dyn_cast<FunctionDecl>(N)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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}}

@cor3ntin cor3ntin merged commit aafad2d into llvm:main Nov 17, 2023
4 checks passed
sr-tream pushed a commit to sr-tream/llvm-project that referenced this pull request Nov 20, 2023
…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.
zahiraam pushed a commit to zahiraam/llvm-project that referenced this pull request Nov 20, 2023
…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.
ldionne added a commit to ldionne/llvm-project that referenced this pull request Nov 23, 2023
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.
@kamaub
Copy link
Contributor

kamaub commented Nov 27, 2023

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-Wno-deprecated-declarations specified in the gtest CMakeList.txt appropriate to temporarily handle them until the third-party unittest can be updated?

@ldionne
Copy link
Member

ldionne commented Nov 28, 2023

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 -Wno-deprecated until you're able to update to a version of Google Test that has fixed this issue?

kamaub added a commit that referenced this pull request Dec 5, 2023
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.
kamaub referenced this pull request Dec 5, 2023
These test cases fail when the libcxx and libcxxabi runtimes are
built on Linux PowerPC. XFailing them until the issue is resolved.
ldionne added a commit to ldionne/llvm-project that referenced this pull request Jan 29, 2024
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.
ldionne added a commit that referenced this pull request Jan 30, 2024
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants