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@-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@-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@-1 {{is a constructor name}} + // expected-warning@-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@-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@-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@-2 {{'template' keyword outside of a template}} + // expected-warning@-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@-1 {{'template' keyword outside of a template}} + // expected-warning@-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@-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@-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@-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@-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@-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@-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@-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@-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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits