[clang] [clang] deprecate alias, class templates without arg list after template kw (PR #94789)

via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 7 11:53:25 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Erick Velez (evelez7)

<details>
<summary>Changes</summary>

Deprecate the use of the template keyword before the qualified name of an alias or class template without a template argument list. Introduced in [P1787](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1787r6.html), with current wording [here](https://eel.is/c++draft/depr.template.template).

---

Patch is 20.29 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/94789.diff


23 Files Affected:

- (modified) clang/include/clang/Basic/DiagnosticParseKinds.td (+4) 
- (modified) clang/lib/Parse/ParseTemplate.cpp (+4) 
- (modified) clang/test/CXX/drs/cwg0xx.cpp (+1) 
- (modified) clang/test/CXX/drs/cwg10xx.cpp (+2-1) 
- (modified) clang/test/CXX/drs/cwg13xx.cpp (+4) 
- (modified) clang/test/CXX/drs/cwg17xx.cpp (+1) 
- (modified) clang/test/CXX/drs/cwg3xx.cpp (+1) 
- (modified) clang/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp (+1) 
- (modified) clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp (+1) 
- (modified) clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp (+1-1) 
- (modified) clang/test/CXX/temp/temp.param/p15-cxx0x.cpp (+2-2) 
- (modified) clang/test/CXX/temp/temp.res/temp.local/p1.cpp (+2-2) 
- (modified) clang/test/PCH/cxx-templates.cpp (-4) 
- (modified) clang/test/PCH/cxx-templates.h (-3) 
- (modified) clang/test/SemaCXX/nested-name-spec-locations.cpp (+1-1) 
- (modified) clang/test/SemaCXX/redeclared-alias-template.cpp (+1-1) 
- (modified) clang/test/SemaTemplate/alias-church-numerals.cpp (+1-2) 
- (modified) clang/test/SemaTemplate/alias-template-template-param.cpp (+1-2) 
- (modified) clang/test/SemaTemplate/concepts-GH53354.cpp (+1-2) 
- (modified) clang/test/SemaTemplate/default-arguments.cpp (+1-1) 
- (modified) clang/test/SemaTemplate/instantiate-self.cpp (+1-1) 
- (modified) clang/test/SemaTemplate/instantiate-template-template-parm.cpp (+1-1) 
- (modified) clang/test/SemaTemplate/temp-param-subst-linear.cpp (+1-2) 


``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index d8c3fee7841f4..661bb6059767b 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -891,6 +891,10 @@ def missing_template_arg_list_after_template_kw : Extension<
   "a template argument list is expected after a name prefixed by the template "
   "keyword">, InGroup<DiagGroup<"missing-template-arg-list-after-template-kw">>,
   DefaultError;
+def warn_missing_template_arg_list_after_template_kw_deprecated : Warning<
+  "the use of the keyword template before the qualified name of a class or "
+  "alias template without a template argument list is deprecated">,
+  InGroup<DiagGroup<"warn-missing-template-arg-list-after-template-kw-deprecated-deprecated">>;
 
 def err_missing_dependent_template_keyword : Error<
   "use 'template' keyword to treat '%0' as a dependent template name">;
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index a5130f56600e5..e44a70ffda1af 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -1420,6 +1420,10 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() {
       UnqualifiedId Name;
       Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
       ConsumeToken(); // the identifier
+      if (Tok.isNot(tok::less)) {
+        Diag(Tok.getLocation(),
+             diag::warn_missing_template_arg_list_after_template_kw_deprecated);
+      }
 
       TryConsumeToken(tok::ellipsis, EllipsisLoc);
 
diff --git a/clang/test/CXX/drs/cwg0xx.cpp b/clang/test/CXX/drs/cwg0xx.cpp
index fe3e0cfc1d421..3204327b8e670 100644
--- a/clang/test/CXX/drs/cwg0xx.cpp
+++ b/clang/test/CXX/drs/cwg0xx.cpp
@@ -1422,6 +1422,7 @@ namespace cwg96 { // cwg96: sup P1787
     // expected-error at -1 {{a template argument list is expected after a name prefixed by the template keyword}}
     A::template S<int> s;
     B<A::template S> b;
+    // expected-warning at -1 {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
   }
 }
 
diff --git a/clang/test/CXX/drs/cwg10xx.cpp b/clang/test/CXX/drs/cwg10xx.cpp
index 58d552942c77c..0db9ab3b3c267 100644
--- a/clang/test/CXX/drs/cwg10xx.cpp
+++ b/clang/test/CXX/drs/cwg10xx.cpp
@@ -40,7 +40,8 @@ namespace cwg1004 { // cwg1004: 5
   // This example (from the standard) is actually ill-formed, because
   // name lookup of "T::template A" names the constructor.
   template<class T, template<class> class U = T::template A> struct Third { };
-  // expected-error at -1 {{is a constructor name}}
+  // expected-warning at -1 {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
+  // expected-error at -2 {{is a constructor name}}
   //   expected-note@#cwg1004-t {{in instantiation of default argument}}
   Third<A<int> > t; // #cwg1004-t
 }
diff --git a/clang/test/CXX/drs/cwg13xx.cpp b/clang/test/CXX/drs/cwg13xx.cpp
index 416de7c536b1a..560d3cf22dafb 100644
--- a/clang/test/CXX/drs/cwg13xx.cpp
+++ b/clang/test/CXX/drs/cwg13xx.cpp
@@ -109,10 +109,12 @@ namespace cwg1310 { // cwg1310: 5
     TT<W<int>::template W> tt2;
     // expected-error at -1 {{ISO C++ specifies that qualified reference to 'W' is a constructor name rather than a template name in this context, despite preceding 'template' keyword}}
     // cxx98-error at -2 {{'template' keyword outside of a template}}
+    // expected-warning at -3 {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
     TT<W<int>::WBase> tt3;
     TTy<W<int>::WBase> tt3a;
     TT<W<int>::template WBase> tt4;
     // cxx98-error at -1 {{'template' keyword outside of a template}}
+    // expected-warning at -2 {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
 
     W<int> w;
     (void)w.W::W::n;
@@ -134,6 +136,7 @@ namespace cwg1310 { // cwg1310: 5
     // expected-error at -1 {{ISO C++ specifies that qualified reference to 'W' is a constructor name rather than a type in this context, despite preceding 'typename' keyword}}
     TT<W::template W> tt3;
     // expected-error at -1 {{ISO C++ specifies that qualified reference to 'W' is a constructor name rather than a template name in this context, despite preceding 'template' keyword}}
+    // expected-warning at -2 {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
   }
   template<typename W>
   void wt_test_good() {
@@ -141,6 +144,7 @@ namespace cwg1310 { // cwg1310: 5
     typename W::template W<int>::X w4x;
     TTy<typename W::WBase> tt4;
     TT<W::template WBase> tt5;
+    // expected-warning at -1 {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
 
     W w;
     (void)w.W::W::n;
diff --git a/clang/test/CXX/drs/cwg17xx.cpp b/clang/test/CXX/drs/cwg17xx.cpp
index fb53a56923b10..6991477221102 100644
--- a/clang/test/CXX/drs/cwg17xx.cpp
+++ b/clang/test/CXX/drs/cwg17xx.cpp
@@ -237,5 +237,6 @@ using Instantiate = Template<Arg>;
 
 template <template <typename> class Template, typename Argument>
 using Bind = Instantiate<Internal<Template>::template Bind, Argument>;
+// expected-warning at -1 {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
 #endif
 } // namespace cwg1794
diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp
index 94227dc031c6a..4aef7167efd03 100644
--- a/clang/test/CXX/drs/cwg3xx.cpp
+++ b/clang/test/CXX/drs/cwg3xx.cpp
@@ -1673,6 +1673,7 @@ namespace cwg398 { // cwg398: yes
     template <class T> void f(typename T::Y *) {} // #cwg398-f
     template <class T> void g(X<T::N> *) {} // #cwg398-g
     template <class T> void h(Z<T::template TT> *) {} // #cwg398-h
+    // expected-warning at -1 {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
     struct A {};
     struct B {
       int Y;
diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp
index f1231f61111e3..94732a48e251d 100644
--- a/clang/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp
@@ -204,6 +204,7 @@ namespace TemplateTemplateApply {
   template<typename T, typename ...Meta>
   struct apply_each_nested {
     typedef typename apply_each<T, Meta::template apply...>::type type;
+    // expected-warning at -1 {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
   };
 
   struct add_reference_meta {
diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
index 30e7c65dac91c..34dbd5bc4bd1c 100644
--- a/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp
@@ -118,6 +118,7 @@ namespace PacksAtDifferentLevels {
     template<typename ...Types2>
     struct Inner<tuple<pair<Types1, Types2>...>,
                  metafun_tuple<some_function_object<Types1, Types2>::template result_of...> > {
+    // expected-warning at -1 {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
       static const unsigned value = 1;
     };
   };
diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
index 3c500c2c4dc4a..7033bd35cc627 100644
--- a/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.variadic/p5.cpp
@@ -207,7 +207,7 @@ struct alignas(Types) TestUnexpandedDecls : T{ // expected-error{{expression con
     struct default_template_args_1;
   template<int = static_cast<Types>(0)> // expected-error{{default argument contains unexpanded parameter pack 'Types'}}
     struct default_template_args_2;
-  template<template<typename> class = Types::template apply> // expected-error{{default argument contains unexpanded parameter pack 'Types'}}
+  template<template<typename> class = Types::template apply> // expected-error{{default argument contains unexpanded parameter pack 'Types'}} // expected-warning{{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
     struct default_template_args_3;
 
   template<Types value> // expected-error{{non-type template parameter type contains unexpanded parameter pack 'Types'}}
diff --git a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
index 83144a494937b..dc43f82e36091 100644
--- a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
+++ b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
@@ -87,11 +87,11 @@ template<place...X> struct takedrop_impl<places<X...>> {
 
 template<unsigned N, typename...Ts> struct take {
   using type = typename takedrop_impl<typename make_places<N>::type>::
-    template inner<wrap<Ts>::template inner...>::take; // expected-error {{too few template arguments}}
+    template inner<wrap<Ts>::template inner...>::take; // expected-error {{too few template arguments}} // expected-warning {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
 };
 template<unsigned N, typename...Ts> struct drop {
   using type = typename takedrop_impl<typename make_places<N>::type>::
-    template inner<wrap<Ts>::template inner...>::drop; // expected-error {{too few template arguments}}
+    template inner<wrap<Ts>::template inner...>::drop; // expected-error {{too few template arguments}} // expected-warning {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
 };
 
 using T1 = take<3, int, char, double, long>::type; // expected-note {{previous}}
diff --git a/clang/test/CXX/temp/temp.res/temp.local/p1.cpp b/clang/test/CXX/temp/temp.res/temp.local/p1.cpp
index faa85cb5fce30..27bad6847b67e 100644
--- a/clang/test/CXX/temp/temp.res/temp.local/p1.cpp
+++ b/clang/test/CXX/temp/temp.res/temp.local/p1.cpp
@@ -23,7 +23,7 @@ template<typename T> struct A {
 
     //   as a template-argument for a template template-parameter,
     TempTemp<A> a_as_temp;
-    TempTemp<B::template C> c_as_temp;
+    TempTemp<B::template C> c_as_temp; // expected-warning {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
 
     //   or as the final identifier in the elaborated-type-specifier of a friend
     //   class template declaration,
@@ -42,7 +42,7 @@ template<typename T> struct A {
     void f(T &t) {
       use<A>(t); // expected-error {{no matching function}}
       if constexpr (&id<T> != &id<int>)
-        use<B::template C>(t); // expected-error {{no matching function}}
+        use<B::template C>(t); // expected-error {{no matching function}} // expected-warning {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
     }
   };
 };
diff --git a/clang/test/PCH/cxx-templates.cpp b/clang/test/PCH/cxx-templates.cpp
index 11ad401de23a8..0e518d24d8597 100644
--- a/clang/test/PCH/cxx-templates.cpp
+++ b/clang/test/PCH/cxx-templates.cpp
@@ -176,10 +176,6 @@ namespace DependentTemplateName {
   struct HasMember {
     template <class T> struct Member;
   };
-
-  void test() {
-    getWithIdentifier<HasMember>();
-  }
 }
 
 namespace ClassTemplateCycle {
diff --git a/clang/test/PCH/cxx-templates.h b/clang/test/PCH/cxx-templates.h
index 95d684e4a92db..367664237fcb0 100644
--- a/clang/test/PCH/cxx-templates.h
+++ b/clang/test/PCH/cxx-templates.h
@@ -451,9 +451,6 @@ namespace DependentMemberExpr {
 namespace DependentTemplateName {
   template <template <class> class Template>
   struct TakesClassTemplate {};
-
-  template <class T>
-  TakesClassTemplate<T::template Member> getWithIdentifier();
 }
 
 namespace ClassTemplateCycle {
diff --git a/clang/test/SemaCXX/nested-name-spec-locations.cpp b/clang/test/SemaCXX/nested-name-spec-locations.cpp
index 048d4baf135bf..90a6b5ec222da 100644
--- a/clang/test/SemaCXX/nested-name-spec-locations.cpp
+++ b/clang/test/SemaCXX/nested-name-spec-locations.cpp
@@ -141,7 +141,7 @@ struct DependentTemplateTemplateArgumentTester {
               typename add_reference<U>::type
               * // expected-error{{declared as a pointer to a reference of type}}
             >::
-            template X>
+            template X> // expected-warning{{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
     type;
 };
 
diff --git a/clang/test/SemaCXX/redeclared-alias-template.cpp b/clang/test/SemaCXX/redeclared-alias-template.cpp
index 4828986f96a61..c833a69d98b17 100644
--- a/clang/test/SemaCXX/redeclared-alias-template.cpp
+++ b/clang/test/SemaCXX/redeclared-alias-template.cpp
@@ -10,7 +10,7 @@ template<typename T2, typename T1> using B = T1; // expected-error {{type alias
 
 template<typename> struct S;
 template<template<typename> class F> using FInt = F<int>;
-template<typename X> using SXRInt = FInt<S<X>::template R>;
+template<typename X> using SXRInt = FInt<S<X>::template R>; // expected-warning {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
 template<typename X> using SXRInt = typename S<X>::template R<int>; // ok, redeclaration.
 
 template<template<typename> class> struct TT;
diff --git a/clang/test/SemaTemplate/alias-church-numerals.cpp b/clang/test/SemaTemplate/alias-church-numerals.cpp
index a1613230ac0d1..c574484b9f988 100644
--- a/clang/test/SemaTemplate/alias-church-numerals.cpp
+++ b/clang/test/SemaTemplate/alias-church-numerals.cpp
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
-// expected-no-diagnostics
 
 template<template<template<typename> class, typename> class T, template<typename> class V> struct PartialApply {
   template<typename W> using R = T<V, W>;
@@ -20,7 +19,7 @@ template<template<template<typename> class, typename> class A,
 template<template<template<typename> class, typename> class A,
          template<template<typename> class, typename> class B,
          template<typename> class F,
-         typename X> using Mul = A<PartialApply<B,F>::template R, X>;
+         typename X> using Mul = A<PartialApply<B,F>::template R, X>; // expected-warning {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
 
 template<template<typename> class F, typename X> using Four = Add<Two, Two, F, X>;
 template<template<typename> class F, typename X> using Sixteen = Mul<Four, Four, F, X>;
diff --git a/clang/test/SemaTemplate/alias-template-template-param.cpp b/clang/test/SemaTemplate/alias-template-template-param.cpp
index 0b17d10d0cb66..a98b692b577a1 100644
--- a/clang/test/SemaTemplate/alias-template-template-param.cpp
+++ b/clang/test/SemaTemplate/alias-template-template-param.cpp
@@ -1,8 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-// expected-no-diagnostics
 
 template<template<typename> class D> using C = D<int>;
 
 // Substitution of the alias template transforms the TemplateSpecializationType
 // 'D<int>' into the DependentTemplateSpecializationType 'T::template U<int>'.
-template<typename T> void f(C<T::template U>);
+template<typename T> void f(C<T::template U>); // expected-warning {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
diff --git a/clang/test/SemaTemplate/concepts-GH53354.cpp b/clang/test/SemaTemplate/concepts-GH53354.cpp
index 4fdf8bdd712a4..0d26abbefd333 100644
--- a/clang/test/SemaTemplate/concepts-GH53354.cpp
+++ b/clang/test/SemaTemplate/concepts-GH53354.cpp
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -std=c++20 -verify %s
-// expected-no-diagnostics
 
 template <template <class> class>
 struct S
@@ -8,7 +7,7 @@ struct S
 template <class T>
 concept C1 = requires
 {
-  typename S<T::template value_types>;
+  typename S<T::template value_types>; // expected-warning {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
 };
 
 template <class T>
diff --git a/clang/test/SemaTemplate/default-arguments.cpp b/clang/test/SemaTemplate/default-arguments.cpp
index d5d9687cc90f4..8db8468389ea6 100644
--- a/clang/test/SemaTemplate/default-arguments.cpp
+++ b/clang/test/SemaTemplate/default-arguments.cpp
@@ -107,7 +107,7 @@ struct add_pointer {
   };
 };
 
-template<typename T, template<typename> class X = T::template apply>
+template<typename T, template<typename> class X = T::template apply> // expected-warning{{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
   struct X4;
 int array4[is_same<X4<add_pointer>, 
                    X4<add_pointer, add_pointer::apply> >::value? 1 : -1];
diff --git a/clang/test/SemaTemplate/instantiate-self.cpp b/clang/test/SemaTemplate/instantiate-self.cpp
index 4999a4ad3784d..f095125f06516 100644
--- a/clang/test/SemaTemplate/instantiate-self.cpp
+++ b/clang/test/SemaTemplate/instantiate-self.cpp
@@ -137,7 +137,7 @@ namespace test13 {
     // Cycle via default template argument.
     template<typename T, typename U = typename T::template X<T>> struct X {};
     template<typename T, int U = T::template Y<T>::value> struct Y { static const int value = 0; };
-    template<typename T, template<typename> typename U = T::template Z<T>::template nested> struct Z { template<typename> struct nested; };
+    template<typename T, template<typename> typename U = T::template Z<T>::template nested> struct Z { template<typename> struct nested; }; // expected-warning {{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
   };
   template<typename T> struct Wrap {
     template<typename U> struct W : A::W<T> {};
diff --git a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp
index 39aeeb1c1a6a3..b2a4725e6b62f 100644
--- a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp
+++ b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp
@@ -73,7 +73,7 @@ namespace PR8629 {
     template<class U> void g()
     {
       typedef Inner<U> Init;
-      X0<Init::template VeryInner>::apply();
+      X0<Init::template VeryInner>::apply(); // expected-warning{{the use of the keyword template before the qualified name of a class or alias template without a template argument list is deprecated}}
     }
     template<int N> void f ()
     {
diff --git a/clang/test/SemaTemplate/temp-param-subst-linear.cpp b/clang/test/SemaTemplate/temp-param-subst-linear.cpp
index fd93aa568553f..7df6677a6e2bf 100644
--- a/clang/test/SemaTemplate/temp-param-subst-linear.cpp
+++ b/clang/test/SemaTemplate/temp-param-subst-linear.cpp
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -std=c++17 %s -verify
-// expected-no-diagnostics
 
 // This test attempts to ensure that the below template parameter pack
 // splitting technique executes in linear time in the number of template
@@ -33,7 +32,7 @@ struct SplitAtIndex;
 template<typename ...T, unsigned N, typename ...NUnsigneds>
 struct SplitAtIndex<TypeList<T...>, N, TypeList<NUnsigneds...>> :
   detail::Splitter<NUnsigneds...>::
-    template Split<detail::TypeWrapper<T>::template AsTemplate...> {};
+    template Split<detail::TypeWrapper<T>::template AsTemplate...> {}; // expected-warning {{the use of the k...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/94789


More information about the cfe-commits mailing list