[clang] 8a334af - [clang] Remove the deprecated flag `-frelaxed-template-template-args`. (#111894)

via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 29 11:57:10 PST 2025


Author: Matheus Izvekov
Date: 2025-01-29T16:57:05-03:00
New Revision: 8a334af417ff2ef49e0bc74f9421b4f3aa479805

URL: https://github.com/llvm/llvm-project/commit/8a334af417ff2ef49e0bc74f9421b4f3aa479805
DIFF: https://github.com/llvm/llvm-project/commit/8a334af417ff2ef49e0bc74f9421b4f3aa479805.diff

LOG: [clang] Remove the deprecated flag `-frelaxed-template-template-args`. (#111894)

This flag has been deprecated since Clang 19, having been the default
since then.

It has remained because its negation was still useful to work around
backwards compatibility breaking changes from P0522.

However, in Clang 20 we have landed various changes which implemented
P3310R2 and beyond, which solve almost all of the expected issues, the
known remaining few being a bit obscure.

So this change removes the flag completely and all of its implementation
and support code.

Hopefully any remaining users can just stop using the flag. If there are
still important issues remaining, this removal will also shake the tree
and help us know.

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticDriverKinds.td
    clang/include/clang/Basic/DiagnosticGroups.td
    clang/include/clang/Basic/LangOptions.def
    clang/include/clang/Driver/Options.td
    clang/include/clang/Sema/Sema.h
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/lib/Frontend/InitPreprocessor.cpp
    clang/lib/Sema/SemaTemplate.cpp
    clang/test/Lexer/cxx-features.cpp
    clang/test/SemaTemplate/cwg2398.cpp
    clang/www/cxx_status.html

Removed: 
    clang/test/Driver/frelaxed-template-template-args.cpp


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 7fafe2807bd388..6397d43616fdde 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -73,6 +73,11 @@ C++17 Feature Support
 Resolutions to C++ Defect Reports
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+- The flag `-frelaxed-template-template-args`
+  and its negation have been removed, having been deprecated since the previous
+  two releases. The improvements to template template parameter matching implemented
+  in the previous release, as described in P3310 and P3579, made this flag unnecessary.
+
 C Language Changes
 ------------------
 

diff  --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 288786b8ce9399..8d599c96eb4fbf 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -445,9 +445,6 @@ def warn_drv_clang_unsupported : Warning<
   "the clang compiler does not support '%0'">;
 def warn_drv_deprecated_arg : Warning<
   "argument '%0' is deprecated%select{|, use '%2' instead}1">, InGroup<Deprecated>;
-def warn_drv_deprecated_arg_no_relaxed_template_template_args : Warning<
-  "argument '-fno-relaxed-template-template-args' is deprecated">,
-  InGroup<DeprecatedNoRelaxedTemplateTemplateArgs>;
 def warn_drv_deprecated_arg_ofast : Warning<
   "argument '-Ofast' is deprecated; use '-O3 -ffast-math' for the same behavior,"
   " or '-O3' to enable only conforming optimizations">,

diff  --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 209792f851b6ae..527e588d46a049 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -102,7 +102,6 @@ def EnumConversion : DiagGroup<"enum-conversion",
                                [EnumEnumConversion,
                                 EnumFloatConversion,
                                 EnumCompareConditional]>;
-def DeprecatedNoRelaxedTemplateTemplateArgs : DiagGroup<"deprecated-no-relaxed-template-template-args">;
 def DeprecatedOFast : DiagGroup<"deprecated-ofast">;
 def ObjCSignedCharBoolImplicitIntConversion :
   DiagGroup<"objc-signed-char-bool-implicit-int-conversion">;
@@ -230,7 +229,6 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
                                           DeprecatedLiteralOperator,
                                           DeprecatedPragma,
                                           DeprecatedRegister,
-                                          DeprecatedNoRelaxedTemplateTemplateArgs,
                                           DeprecatedOFast,
                                           DeprecatedThisCapture,
                                           DeprecatedType,

diff  --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 1bcec212fd332e..cb55f09acc076c 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -160,7 +160,6 @@ LANGOPT(GNUAsm            , 1, 1, "GNU-style inline assembly")
 LANGOPT(Coroutines        , 1, 0, "C++20 coroutines")
 LANGOPT(CoroAlignedAllocation, 1, 0, "prefer Aligned Allocation according to P2014 Option 2")
 LANGOPT(DllExportInlines  , 1, 1, "dllexported classes dllexport inline methods")
-LANGOPT(RelaxedTemplateTemplateArgs, 1, 1, "C++17 relaxed matching of template template arguments")
 LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library features")
 LANGOPT(RetainSubstTemplateTypeParmTypeAstNodes, 1, 0, "retain SubstTemplateTypeParmType nodes in the AST's representation of alias template specializations")
 

diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 1af633e59d0bba..ba5600e1912a63 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -3557,11 +3557,6 @@ defm application_extension : BoolFOption<"application-extension",
   PosFlag<SetTrue, [], [ClangOption, CC1Option],
           "Restrict code to those available for App Extensions">,
   NegFlag<SetFalse>>;
-defm relaxed_template_template_args : BoolFOption<"relaxed-template-template-args",
-  LangOpts<"RelaxedTemplateTemplateArgs">, DefaultTrue,
-  PosFlag<SetTrue, [], [], "Enable">,
-  NegFlag<SetFalse, [], [CC1Option], "Disable">,
-  BothFlags<[], [ClangOption], " C++17 relaxed template template argument matching">>;
 defm retain_subst_template_type_parm_type_ast_nodes : BoolFOption<"retain-subst-template-type-parm-type-ast-nodes",
   LangOpts<"RetainSubstTemplateTypeParmTypeAstNodes">, DefaultFalse,
   PosFlag<SetTrue, [], [CC1Option], "Enable">,

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d0fc735be5f763..6b4959f972cfe5 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11837,17 +11837,6 @@ class Sema final : public SemaBase {
     /// \endcode
     TPL_TemplateTemplateParmMatch,
 
-    /// We are matching the template parameter lists of a template
-    /// template argument against the template parameter lists of a template
-    /// template parameter.
-    ///
-    /// \code
-    /// template<template<int Value> class Metafun> struct X;
-    /// template<int Value> struct integer_c;
-    /// X<integer_c> xic;
-    /// \endcode
-    TPL_TemplateTemplateArgumentMatch,
-
     /// We are determining whether the template-parameters are equivalent
     /// according to C++ [temp.over.link]/6. This comparison does not consider
     /// constraints.

diff  --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 589de953be5be1..70e5e9847dff6f 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7502,20 +7502,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   Args.addOptOutFlag(CmdArgs, options::OPT_fassume_unique_vtables,
                      options::OPT_fno_assume_unique_vtables);
 
-  // -frelaxed-template-template-args is deprecated.
-  if (Arg *A =
-          Args.getLastArg(options::OPT_frelaxed_template_template_args,
-                          options::OPT_fno_relaxed_template_template_args)) {
-    if (A->getOption().matches(
-            options::OPT_fno_relaxed_template_template_args)) {
-      D.Diag(diag::warn_drv_deprecated_arg_no_relaxed_template_template_args);
-      CmdArgs.push_back("-fno-relaxed-template-template-args");
-    } else {
-      D.Diag(diag::warn_drv_deprecated_arg)
-          << A->getAsString(Args) << /*hasReplacement=*/false;
-    }
-  }
-
   // -fsized-deallocation is on by default in C++14 onwards and otherwise off
   // by default.
   Args.addLastArg(CmdArgs, options::OPT_fsized_deallocation,

diff  --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index 542e26b6a129b4..77833f5d1defb2 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -729,8 +729,8 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
   }
   if (LangOpts.AlignedAllocation && !LangOpts.AlignedAllocationUnavailable)
     Builder.defineMacro("__cpp_aligned_new", "201606L");
-  if (LangOpts.RelaxedTemplateTemplateArgs)
-    Builder.defineMacro("__cpp_template_template_args", "201611L");
+
+  Builder.defineMacro("__cpp_template_template_args", "201611L");
 
   // C++20 features.
   if (LangOpts.CPlusPlus20) {

diff  --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 3944c4f67bab9a..35ece88c603ddd 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -7399,11 +7399,6 @@ bool Sema::CheckTemplateTemplateArgument(
       << Template;
   }
 
-  if (!getLangOpts().RelaxedTemplateTemplateArgs)
-    return !TemplateParameterListsAreEqual(
-        Template->getTemplateParameters(), Params, /*Complain=*/true,
-        TPL_TemplateTemplateArgumentMatch, Arg.getLocation());
-
   // C++1z [temp.arg.template]p3: (DR 150)
   //   A template-argument matches a template template-parameter P when P
   //   is at least as specialized as the template-argument A.
@@ -7775,9 +7770,7 @@ static bool MatchTemplateParameterKind(
   // However, if we are matching a template template argument to a
   // template template parameter, the template template parameter can have
   // a parameter pack where the template template argument does not.
-  if (Old->isTemplateParameterPack() != New->isTemplateParameterPack() &&
-      !(Kind == Sema::TPL_TemplateTemplateArgumentMatch &&
-        Old->isTemplateParameterPack())) {
+  if (Old->isTemplateParameterPack() != New->isTemplateParameterPack()) {
     if (Complain) {
       unsigned NextDiag = diag::err_template_parameter_pack_non_pack;
       if (TemplateArgLoc.isValid()) {
@@ -7803,37 +7796,28 @@ static bool MatchTemplateParameterKind(
                                     = dyn_cast<NonTypeTemplateParmDecl>(Old)) {
     NonTypeTemplateParmDecl *NewNTTP = cast<NonTypeTemplateParmDecl>(New);
 
-    // If we are matching a template template argument to a template
-    // template parameter and one of the non-type template parameter types
-    // is dependent, then we must wait until template instantiation time
-    // to actually compare the arguments.
-    if (Kind != Sema::TPL_TemplateTemplateArgumentMatch ||
-        (!OldNTTP->getType()->isDependentType() &&
-         !NewNTTP->getType()->isDependentType())) {
-      // C++20 [temp.over.link]p6:
-      //   Two [non-type] template-parameters are equivalent [if] they have
-      //   equivalent types ignoring the use of type-constraints for
-      //   placeholder types
-      QualType OldType = S.Context.getUnconstrainedType(OldNTTP->getType());
-      QualType NewType = S.Context.getUnconstrainedType(NewNTTP->getType());
-      if (!S.Context.hasSameType(OldType, NewType)) {
-        if (Complain) {
-          unsigned NextDiag = diag::err_template_nontype_parm_
diff erent_type;
-          if (TemplateArgLoc.isValid()) {
-            S.Diag(TemplateArgLoc,
-                   diag::err_template_arg_template_params_mismatch);
-            NextDiag = diag::note_template_nontype_parm_
diff erent_type;
-          }
-          S.Diag(NewNTTP->getLocation(), NextDiag)
-            << NewNTTP->getType()
-            << (Kind != Sema::TPL_TemplateMatch);
-          S.Diag(OldNTTP->getLocation(),
-                 diag::note_template_nontype_parm_prev_declaration)
-            << OldNTTP->getType();
+    // C++20 [temp.over.link]p6:
+    //   Two [non-type] template-parameters are equivalent [if] they have
+    //   equivalent types ignoring the use of type-constraints for
+    //   placeholder types
+    QualType OldType = S.Context.getUnconstrainedType(OldNTTP->getType());
+    QualType NewType = S.Context.getUnconstrainedType(NewNTTP->getType());
+    if (!S.Context.hasSameType(OldType, NewType)) {
+      if (Complain) {
+        unsigned NextDiag = diag::err_template_nontype_parm_
diff erent_type;
+        if (TemplateArgLoc.isValid()) {
+          S.Diag(TemplateArgLoc,
+                 diag::err_template_arg_template_params_mismatch);
+          NextDiag = diag::note_template_nontype_parm_
diff erent_type;
         }
-
-        return false;
+        S.Diag(NewNTTP->getLocation(), NextDiag)
+            << NewNTTP->getType() << (Kind != Sema::TPL_TemplateMatch);
+        S.Diag(OldNTTP->getLocation(),
+               diag::note_template_nontype_parm_prev_declaration)
+            << OldNTTP->getType();
       }
+
+      return false;
     }
   }
   // For template template parameters, check the template parameter types.
@@ -7853,7 +7837,6 @@ static bool MatchTemplateParameterKind(
   }
 
   if (Kind != Sema::TPL_TemplateParamsEquivalent &&
-      Kind != Sema::TPL_TemplateTemplateArgumentMatch &&
       !isa<TemplateTemplateParmDecl>(Old)) {
     const Expr *NewC = nullptr, *OldC = nullptr;
 
@@ -7924,7 +7907,7 @@ bool Sema::TemplateParameterListsAreEqual(
     const TemplateCompareNewDeclInfo &NewInstFrom, TemplateParameterList *New,
     const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain,
     TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc) {
-  if (Old->size() != New->size() && Kind != TPL_TemplateTemplateArgumentMatch) {
+  if (Old->size() != New->size()) {
     if (Complain)
       DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind,
                                                  TemplateArgLoc);
@@ -7941,40 +7924,18 @@ bool Sema::TemplateParameterListsAreEqual(
   TemplateParameterList::iterator NewParm = New->begin();
   TemplateParameterList::iterator NewParmEnd = New->end();
   for (TemplateParameterList::iterator OldParm = Old->begin(),
-                                    OldParmEnd = Old->end();
-       OldParm != OldParmEnd; ++OldParm) {
-    if (Kind != TPL_TemplateTemplateArgumentMatch ||
-        !(*OldParm)->isTemplateParameterPack()) {
-      if (NewParm == NewParmEnd) {
-        if (Complain)
-          DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind,
-                                                     TemplateArgLoc);
-
-        return false;
-      }
-
-      if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm,
-                                      OldInstFrom, Complain, Kind,
-                                      TemplateArgLoc))
-        return false;
-
-      ++NewParm;
-      continue;
-    }
-
-    // C++0x [temp.arg.template]p3:
-    //   [...] When P's template- parameter-list contains a template parameter
-    //   pack (14.5.3), the template parameter pack will match zero or more
-    //   template parameters or template parameter packs in the
-    //   template-parameter-list of A with the same type and form as the
-    //   template parameter pack in P (ignoring whether those template
-    //   parameters are template parameter packs).
-    for (; NewParm != NewParmEnd; ++NewParm) {
-      if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm,
-                                      OldInstFrom, Complain, Kind,
-                                      TemplateArgLoc))
-        return false;
+                                       OldParmEnd = Old->end();
+       OldParm != OldParmEnd; ++OldParm, ++NewParm) {
+    if (NewParm == NewParmEnd) {
+      if (Complain)
+        DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind,
+                                                   TemplateArgLoc);
+      return false;
     }
+    if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm,
+                                    OldInstFrom, Complain, Kind,
+                                    TemplateArgLoc))
+      return false;
   }
 
   // Make sure we exhausted all of the arguments.
@@ -7986,8 +7947,7 @@ bool Sema::TemplateParameterListsAreEqual(
     return false;
   }
 
-  if (Kind != TPL_TemplateTemplateArgumentMatch &&
-      Kind != TPL_TemplateParamsEquivalent) {
+  if (Kind != TPL_TemplateParamsEquivalent) {
     const Expr *NewRC = New->getRequiresClause();
     const Expr *OldRC = Old->getRequiresClause();
 

diff  --git a/clang/test/Driver/frelaxed-template-template-args.cpp b/clang/test/Driver/frelaxed-template-template-args.cpp
deleted file mode 100644
index 7a7fd6f0bbc8f9..00000000000000
--- a/clang/test/Driver/frelaxed-template-template-args.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-// RUN: %clang -fsyntax-only -### %s 2>&1 | FileCheck --check-prefix=CHECK-DEF %s
-// RUN: %clang -fsyntax-only -frelaxed-template-template-args %s 2>&1 | FileCheck --check-prefix=CHECK-ON %s
-// RUN: %clang -fsyntax-only -fno-relaxed-template-template-args %s 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
-// RUN: %clang -fsyntax-only -fno-relaxed-template-template-args -Wno-deprecated-no-relaxed-template-template-args %s 2>&1 | FileCheck --check-prefix=CHECK-DIS --allow-empty %s
-
-// CHECK-DEF-NOT: "-cc1"{{.*}} "-fno-relaxed-template-template-args"
-// CHECK-ON:  warning: argument '-frelaxed-template-template-args' is deprecated [-Wdeprecated]
-// CHECK-OFF: warning: argument '-fno-relaxed-template-template-args' is deprecated [-Wdeprecated-no-relaxed-template-template-args]
-// CHECK-DIS-NOT: warning: argument '-fno-relaxed-template-template-args' is deprecated

diff  --git a/clang/test/Lexer/cxx-features.cpp b/clang/test/Lexer/cxx-features.cpp
index 3a60318d3f2317..b423e94b26acad 100644
--- a/clang/test/Lexer/cxx-features.cpp
+++ b/clang/test/Lexer/cxx-features.cpp
@@ -7,7 +7,6 @@
 // RUN: %clang_cc1 -std=c++2c -fcxx-exceptions -verify %s
 
 //
-// RUN: %clang_cc1 -std=c++17 -fcxx-exceptions -fno-relaxed-template-template-args -DNO_RELAXED_TEMPLATE_TEMPLATE_ARGS=1 -verify %s
 // RUN: %clang_cc1 -std=c++17 -fcxx-exceptions -DCONCEPTS_TS=1 -verify %s
 // RUN: %clang_cc1 -std=c++14 -fno-rtti -fno-threadsafe-statics -verify %s -DNO_EXCEPTIONS -DNO_RTTI -DNO_THREADSAFE_STATICS
 // RUN: %clang_cc1 -std=c++14 -fchar8_t -DNO_EXCEPTIONS -DCHAR8_T -verify %s
@@ -239,9 +238,7 @@
 #error "wrong value for __cpp_nontype_template_args"
 #endif
 
-#if !defined(NO_RELAXED_TEMPLATE_TEMPLATE_ARGS) \
-    ? check(template_template_args, 201611, 201611, 201611, 201611, 201611, 201611, 201611) \
-    : check(template_template_args, 0, 0, 0, 0, 0, 0, 0)
+#if check(template_template_args, 201611, 201611, 201611, 201611, 201611, 201611, 201611)
 #error "wrong value for __cpp_template_template_args"
 #endif
 

diff  --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp
index dccb17c48d3256..1728f90af287b0 100644
--- a/clang/test/SemaTemplate/cwg2398.cpp
+++ b/clang/test/SemaTemplate/cwg2398.cpp
@@ -1,14 +1,12 @@
-// RUN: %clang_cc1 %s -fsyntax-only -std=c++23                                     -verify=expected,new
-// RUN: %clang_cc1 %s -fsyntax-only -std=c++23 -fno-relaxed-template-template-args -verify=expected,old
+// RUN: %clang_cc1 %s -fsyntax-only -std=c++23 -verify
 
 namespace issue1 {
   template<class T, class U = T> class B {};
   template<template<class> class P, class T> void f(P<T>);
-  // new-note at -1 {{deduced type 'B<[...], (default) int>' of 1st parameter does not match adjusted type 'B<[...], float>' of argument [with P = B, T = int]}}
-  // old-note at -2 2{{template template argument has 
diff erent template parameters}}
+  // expected-note at -1 {{deduced type 'B<[...], (default) int>' of 1st parameter does not match adjusted type 'B<[...], float>' of argument [with P = B, T = int]}}
 
   void g() {
-    f(B<int>()); // old-error {{no matching function for call}}
+    f(B<int>());
     f(B<int,float>()); // expected-error {{no matching function for call}}
   }
 } // namespace issue1
@@ -116,41 +114,32 @@ namespace gcc_issue {
   template<class T1, class T2> struct A;
 
   template<template<class T1> class TT1, class T2> struct A<TT1<T2>, typename TT1<T2>::type>;
-  // new-note at -1 {{partial specialization matches}}
+  // expected-note at -1 {{partial specialization matches}}
 
   template<template<class T3, class T4> class TT2, class T5, class T6>
   struct A<TT2<T5, T6>, typename TT2<T5, T5>::type>;
-  // new-note at -1 {{partial specialization matches}}
-  // old-note at -2 {{template is declared here}}
+  // expected-note at -1 {{partial specialization matches}}
 
   template <class T7, class T8 = T7> struct B { using type = int; };
 
   template struct A<B<int>, int>;
-  // new-error at -1 {{ambiguous partial specializations}}
-  // old-error at -2 {{explicit instantiation of undefined template}}
+  // expected-error at -1 {{ambiguous partial specializations}}
 } // namespace gcc_issue
 
 namespace ttp_defaults {
   template <template <class T1> class TT1> struct A {};
-  // old-note at -1 2{{previous template template parameter}}
 
   template <template <class T2> class TT2> void f(A<TT2>);
-  // new-note at -1 {{explicit instantiation candidate}}
-  // old-note at -2 {{invalid explicitly-specified argument for template parameter 'TT2'}}
+  // expected-note at -1 {{explicit instantiation candidate}}
 
   // FIXME: The default arguments on the TTP are not available during partial ordering.
   template <template <class T3, class T4 = float> class TT3> void f(A<TT3>) {};
-  // new-note at -1 {{explicit instantiation candidate}}
-  // old-error at -2 {{template template argument has 
diff erent template parameters}}
-  // old-note at -3 {{too many template parameters}}
+  // expected-note at -1 {{explicit instantiation candidate}}
 
   template <class T5, class T6 = int> struct B;
-  // old-note at -1 {{too many template parameters}}
 
   template void f<B>(A<B>);
-  // new-error at -1 {{partial ordering for explicit instantiation of 'f' is ambiguous}}
-  // old-error at -2 {{template template argument has 
diff erent template parameters}}
-  // old-error at -3 {{explicit instantiation of 'f' does not refer to a function template}}
+  // expected-error at -1 {{partial ordering for explicit instantiation of 'f' is ambiguous}}
 } // namespace ttp_defaults
 
 namespace ttp_only {
@@ -193,16 +182,16 @@ namespace consistency {
     template<template<class, class> class TT1,
              class T1, class T2, class T3, class T4>
     struct A<TT1<T1, T2>, TT1<T3, T4>, typename nondeduced<TT1<T1, T4>>::type> {};
-    // new-note at -1 {{partial specialization matches}}
+    // expected-note at -1 {{partial specialization matches}}
 
     template<template<class> class UU1,
              template<class> class UU2,
              class U1, class U2>
     struct A<UU1<U1>, UU2<U2>, typename nondeduced<UU1<U1>>::type>;
-    // new-note at -1 {{partial specialization matches}}
+    // expected-note at -1 {{partial specialization matches}}
 
     template struct A<B<int>, B<int>, B<int>>;
-    // new-error at -1 {{ambiguous partial specializations}}
+    // expected-error at -1 {{ambiguous partial specializations}}
   } // namespace t2
   namespace t3 {
     template<class T1, class T2, class T3> struct A;
@@ -210,15 +199,15 @@ namespace consistency {
     template<template<class, class> class TT1,
              class T1, class T2, class T3, class T4>
     struct A<TT1<T1, T2>, TT1<T3, T4>, typename nondeduced<TT1<T1, T2>>::type> {};
-    // new-note at -1 {{partial specialization matches}}
+    // expected-note at -1 {{partial specialization matches}}
 
     template<template<class> class UU1,
              class U1, class U2>
     struct A<UU1<U1>, UU1<U2>, typename nondeduced<UU1<U1>>::type>;
-    // new-note at -1 {{partial specialization matches}}
+    // expected-note at -1 {{partial specialization matches}}
 
     template struct A<B<int>, B<int>, B<int>>;
-    // new-error at -1 {{ambiguous partial specializations}}
+    // expected-error at -1 {{ambiguous partial specializations}}
   } // namespace t3
   namespace t4 {
     template<class T1, class T2, class T3> struct A;
@@ -226,15 +215,15 @@ namespace consistency {
     template<template<class, class> class TT1,
              class T1, class T2, class T3, class T4>
     struct A<TT1<T1, T2>, TT1<T3, T4>, typename nondeduced<TT1<T1, T4>>::type> {};
-    // new-note at -1 {{partial specialization matches}}
+    // expected-note at -1 {{partial specialization matches}}
 
     template<template<class> class UU1,
              class U1, class U2>
     struct A<UU1<U1>, UU1<U2>, typename nondeduced<UU1<U1>>::type>;
-    // new-note at -1 {{partial specialization matches}}
+    // expected-note at -1 {{partial specialization matches}}
 
     template struct A<B<int>, B<int>, B<int>>;
-    // new-error at -1 {{ambiguous partial specializations}}
+    // expected-error at -1 {{ambiguous partial specializations}}
   } // namespace t4
   namespace t5 {
     template<class T1, class T2> struct A;
@@ -242,15 +231,15 @@ namespace consistency {
     template<template<class, class> class TT1,
              class T1, class T2, class T3, class T4>
     struct A<TT1<T1, T2>, TT1<T3, T4>> {};
-    // new-note at -1 {{partial specialization matches}}
+    // expected-note at -1 {{partial specialization matches}}
 
     template<template<class> class UU1,
              class U1, class U2>
     struct A<UU1<U1>, UU1<U2>>;
-    // new-note at -1 {{partial specialization matches}}
+    // expected-note at -1 {{partial specialization matches}}
 
     template struct A<B<int>, B<int>>;
-    // new-error at -1 {{ambiguous partial specializations}}
+    // expected-error at -1 {{ambiguous partial specializations}}
   } // namespace t5
   namespace t6 {
     template<class T1, class T2> struct A;
@@ -258,15 +247,15 @@ namespace consistency {
     template<template<class, class> class TT1,
              class T1, class T2, class T3>
     struct A<TT1<T1, T2>, TT1<T1, T3>> {};
-    // new-note at -1 {{partial specialization matches}}
+    // expected-note at -1 {{partial specialization matches}}
 
     template<template<class> class UU1,
              class U1, class U2>
     struct A<UU1<U1>, UU1<U2>>;
-    // new-note at -1 {{partial specialization matches}}
+    // expected-note at -1 {{partial specialization matches}}
 
     template struct A<B<int>, B<int>>;
-    // new-error at -1 {{ambiguous partial specializations}}
+    // expected-error at -1 {{ambiguous partial specializations}}
   } // namespace t6
 } // namespace consistency
 
@@ -275,8 +264,7 @@ namespace classes {
     template<class T, class U> struct A {};
 
     template<template<class> class TT> auto f(TT<int> a) { return a; }
-    // old-note at -1 2{{template template argument has 
diff erent template parameters}}
-    // new-note at -2 2{{substitution failure: too few template arguments}}
+    // expected-note at -1 2{{substitution failure: too few template arguments}}
 
     A<int, float> v1;
     A<int, double> v2;
@@ -292,8 +280,7 @@ namespace classes {
       static constexpr auto val = E1;
     };
     template <template <class T3> class TT> void f(TT<int> v) {
-      // old-note at -1 {{template template argument has 
diff erent template parameters}}
-      // new-note at -2 {{substitution failure: too few template arguments}}
+      // expected-note at -1 {{substitution failure: too few template arguments}}
       static_assert(v.val == 3);
     };
     void test() {
@@ -307,8 +294,7 @@ namespace classes {
     };
 
     template <template <class T3> class TT> void f(TT<int> v) {
-      // old-note at -1 {{template template argument has 
diff erent template parameters}}
-      // new-note at -2 {{deduced type 'A<[...], (no argument), (no argument), (no argument)>' of 1st parameter does not match adjusted type 'A<[...], void, void, void>' of argument [with TT = A]}}
+      // expected-note at -1 {{deduced type 'A<[...], (no argument), (no argument), (no argument)>' of 1st parameter does not match adjusted type 'A<[...], void, void, void>' of argument [with TT = A]}}
       static_assert(v.val == 3);
     };
     void test() {
@@ -327,8 +313,7 @@ namespace classes {
     }
 
     template <template <class T2, int V3> class TT2> auto g(TT2<double, 1>) {
-      // new-note at -1 {{too few template arguments for class template 'A'}}
-      // old-note at -2 {{template template argument has 
diff erent template parameters}}
+      // expected-note at -1 {{too few template arguments for class template 'A'}}
       return f(TT2<int, 2>());
     }
 
@@ -346,13 +331,11 @@ namespace classes {
     };
 
     template <template <class> class TT> TT<float> f(TT<int>);
-    // new-note at -1  {{deduced type 'A<[...], (default) int *>' of 1st parameter does not match adjusted type 'A<[...], double *>' of argument [with TT = A]}}
-    // old-note at -2 2{{template template argument has 
diff erent template parameters}}
+    // expected-note at -1  {{deduced type 'A<[...], (default) int *>' of 1st parameter does not match adjusted type 'A<[...], double *>' of argument [with TT = A]}}
 
-    using X = int*; // new-note {{previous definition is here}}
+    using X = int*; // expected-note {{previous definition is here}}
     using X = decltype(f(A<int>()))::type;
-    // new-error at -1 {{
diff erent types ('decltype(f(A<int>()))::type' (aka 'float *') vs 'int *')}}
-    // old-error at -2 {{no matching function for call}}
+    // expected-error at -1 {{
diff erent types ('decltype(f(A<int>()))::type' (aka 'float *') vs 'int *')}}
 
     using Y = double*;
     using Y = decltype(f(A<int, double*>()))::type;
@@ -363,59 +346,39 @@ namespace classes {
 namespace packs {
   namespace t1 {
     template<template<int, int...> class> struct A {};
-    // new-error at -1 {{non-type parameter of template template parameter cannot be narrowed from type 'int' to 'char'}}
-    // new-note at -2 {{previous template template parameter is here}}
-    // old-note at -3 {{previous non-type template parameter with type 'int' is here}}
+    // expected-error at -1 {{non-type parameter of template template parameter cannot be narrowed from type 'int' to 'char'}}
+    // expected-note at -2 {{previous template template parameter is here}}
 
     template<char> struct B;
-    // old-note at -1 {{template non-type parameter has a 
diff erent type 'char' in template argument}}
-
     template struct A<B>;
-    // new-note at -1 {{has 
diff erent template parameters}}
-    // old-error at -2 {{has 
diff erent template parameters}}
+    // expected-note at -1 {{has 
diff erent template parameters}}
   } // namespace t1
   namespace t2 {
     template<template<char, int...> class> struct A {};
-    // old-note at -1 {{previous non-type template parameter with type 'char' is here}}
-
     template<int> struct B;
-    // old-note at -1 {{template non-type parameter has a 
diff erent type 'int' in template argument}}
-
     template struct A<B>;
-    // old-error at -1 {{has 
diff erent template parameters}}
   } // namespace t2
   namespace t3 {
     template<template<int...> class> struct A {};
-    // new-error at -1 {{non-type parameter of template template parameter cannot be narrowed from type 'int' to 'char'}}
-    // new-note at -2 {{previous template template parameter is here}}
-    // old-note at -3 {{previous non-type template parameter with type 'int' is here}}
+    // expected-error at -1 {{non-type parameter of template template parameter cannot be narrowed from type 'int' to 'char'}}
+    // expected-note at -2 {{previous template template parameter is here}}
 
     template<char> struct B;
-    // old-note at -1 {{template non-type parameter has a 
diff erent type 'char' in template argument}}
-
     template struct A<B>;
-    // new-note at -1 {{has 
diff erent template parameters}}
-    // old-error at -2 {{has 
diff erent template parameters}}
+    // expected-note at -1 {{has 
diff erent template parameters}}
   } // namespace t3
   namespace t4 {
     template<template<char...> class> struct A {};
-    // old-note at -1 {{previous non-type template parameter with type 'char' is here}}
-
     template<int> struct B;
-    // old-note at -1 {{template non-type parameter has a 
diff erent type 'int' in template argument}}
-
     template struct A<B>;
-    // old-error at -1 {{has 
diff erent template parameters}}
   } // namespace t4
 } // namespace packs
 
 namespace fun_tmpl_call {
   namespace match_func {
     template <template <class> class TT> void f(TT<int>) {};
-    // old-note at -1 {{has 
diff erent template parameters}}
     template <class...> struct A {};
     void test() { f(A<int>()); }
-    // old-error at -1 {{no matching function for call to 'f'}}
   } // namespace match_func
   namespace order_func_nonpack {
     template <template <class> class TT> void f(TT<int>) {}
@@ -427,26 +390,21 @@ namespace fun_tmpl_call {
   namespace order_func_pack {
     template <template <class> class TT> void f(TT<int>) = delete;
     template <template <class...> class TT> void f(TT<int>) {}
-
     template <class...> struct A {};
     void test() { f(A<int>()); }
   } // namespace order_func_pack
   namespace match_enum {
     enum A {};
     template<template<A> class TT1> void f(TT1<{}>) {}
-    // old-note at -1 {{invalid explicitly-specified argument}}
     template<int> struct B {};
     template void f<B>(B<{}>);
-    // old-error at -1 {{does not refer to a function template}}
   } // namespace match_enum
   namespace match_method {
     struct A {
       template <template <class> class TT> void f(TT<int>) {};
-      // old-note at -1 {{has 
diff erent template parameters}}
     };
     template <class...> struct B {};
     void test() { A().f(B<int>()); }
-    // old-error at -1 {{no matching member function for call to 'f'}}
   } // namespace match_method
   namespace order_method_nonpack {
     struct A {
@@ -467,12 +425,9 @@ namespace fun_tmpl_call {
   namespace match_conv {
     struct A {
       template <template <class> class TT> operator TT<int>() { return {}; }
-      // old-note at -1 {{
diff erent template parameters}}
     };
     template <class...> struct B {};
-    // old-note at -1 2{{not viable}}
     void test() { B<int> b = A(); }
-    // old-error at -1 {{no viable conversion from 'A' to 'B<int>'}}
   } // namespace match_conv
   namespace order_conv_nonpack {
     struct A {
@@ -536,21 +491,21 @@ namespace regression1 {
 
 namespace constraints {
   template <class T> concept C1 = true;
-  // new-note at -1 {{similar constraint expression here}}
-  // new-note at -2 2{{similar constraint expressions not considered equivalent}}
+  // expected-note at -1 {{similar constraint expression here}}
+  // expected-note at -2 2{{similar constraint expressions not considered equivalent}}
 
   template <class T> concept C2 = C1<T> && true;
-  // new-note at -1 2{{similar constraint expression here}}
+  // expected-note at -1 2{{similar constraint expression here}}
 
   template <class T> concept D1 = true;
-  // new-note at -1 {{similar constraint expressions not considered equivalent}}
+  // expected-note at -1 {{similar constraint expressions not considered equivalent}}
 
   namespace t1 {
-    template<template<C1, class... T1s> class TT1> // new-note {{TT1' declared here}}
+    template<template<C1, class... T1s> class TT1> // expected-note {{TT1' declared here}}
     struct A {};
-    template<D1, class T2> struct B {}; // new-note {{'B' declared here}}
+    template<D1, class T2> struct B {}; // expected-note {{'B' declared here}}
     template struct A<B>;
-    // new-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
+    // expected-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
   } // namespace t1
   namespace t2 {
     template<template<C2, class... T1s> class TT1> struct A {};
@@ -558,34 +513,34 @@ namespace constraints {
     template struct A<B>;
   } // namespace t2
   namespace t3 {
-    template<template<C1, class... T1s> class TT1> // new-note {{'TT1' declared here}}
+    template<template<C1, class... T1s> class TT1> // expected-note {{'TT1' declared here}}
     struct A {};
-    template<C2, class T2> struct B {}; // new-note {{'B' declared here}}
+    template<C2, class T2> struct B {}; // expected-note {{'B' declared here}}
     template struct A<B>;
-    // new-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
+    // expected-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
   } // namespace t2
   namespace t4 {
     // FIXME: This should be accepted.
-    template<template<C1... T1s> class TT1> // new-note {{'TT1' declared here}}
+    template<template<C1... T1s> class TT1> // expected-note {{'TT1' declared here}}
     struct A {};
-    template<C1 T2> struct B {}; // new-note {{'B' declared here}}
+    template<C1 T2> struct B {}; // expected-note {{'B' declared here}}
     template struct A<B>;
-    // new-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
+    // expected-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
   } // namespace t4
   namespace t5 {
     // FIXME: This should be accepted
-    template<template<C2... T1s> class TT1> // new-note {{'TT1' declared here}}
+    template<template<C2... T1s> class TT1> // expected-note {{'TT1' declared here}}
     struct A {};
-    template<C1 T2> struct B {}; // new-note {{'B' declared here}}
+    template<C1 T2> struct B {}; // expected-note {{'B' declared here}}
     template struct A<B>;
-    // new-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
+    // expected-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
   } // namespace t5
   namespace t6 {
-    template<template<C1... T1s> class TT1> // new-note {{'TT1' declared here}}
+    template<template<C1... T1s> class TT1> // expected-note {{'TT1' declared here}}
     struct A {};
-    template<C2 T2> struct B {}; // new-note {{'B' declared here}}
+    template<C2 T2> struct B {}; // expected-note {{'B' declared here}}
     template struct A<B>;
-    // new-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
+    // expected-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
   } // namespace t6
   namespace t7 {
     template<template<class... T1s> class TT1>
@@ -600,19 +555,19 @@ namespace constraints {
     template struct A<B>;
   } // namespace t8
   namespace t9 {
-    template<template<C1... T1s> class TT1> // new-note {{'TT1' declared here}}
+    template<template<C1... T1s> class TT1> // expected-note {{'TT1' declared here}}
     struct A {};
-    template<D1 T2> struct B {}; // new-note {{'B' declared here}}
+    template<D1 T2> struct B {}; // expected-note {{'B' declared here}}
     template struct A<B>;
-    // new-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
+    // expected-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
   } // namespace t9
   namespace t10 {
-    template<template<class...> requires C1<int> class TT1> // new-note {{'TT1' declared here}}
+    template<template<class...> requires C1<int> class TT1> // expected-note {{'TT1' declared here}}
     struct A {};
 
-    template<class> requires C2<int> struct B {}; // new-note {{'B' declared here}}
+    template<class> requires C2<int> struct B {}; // expected-note {{'B' declared here}}
     template struct A<B>;
-    // new-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
+    // expected-error at -1 {{'B' is more constrained than template template parameter 'TT1'}}
   } // namespace t10
   namespace t11 {
     template<template<class...> requires C2<int> class TT1> struct A {};
@@ -640,24 +595,22 @@ namespace nttp_auto {
   namespace t2 {
     // FIXME: Shouldn't accept parameters after a parameter pack.
     template<template<auto... Va1, auto Va2> class> struct A {};
-    // new-error at -1 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('auto' vs 'int')}}
+    // expected-error at -1 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('auto' vs 'int')}}
     // expected-note at -2 {{previous template template parameter is here}}
     template<int... Vi> struct B;
-    // new-note at -1 {{template parameter is declared here}}
-    // old-note at -2 {{too few template parameters}}
+    // expected-note at -1 {{template parameter is declared here}}
     template struct A<B>;
-    // new-note at -1 {{
diff erent template parameters}}
-    // old-error at -2 {{
diff erent template parameters}}
+    // expected-note at -1 {{
diff erent template parameters}}
   } // namespace t2
   namespace t3 {
     // FIXME: Shouldn't accept parameters after a parameter pack.
     template<template<auto... Va1, auto... Va2> class> struct A {};
-    // new-error at -1 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('auto' vs 'int')}}
-    // new-note at -2 {{previous template template parameter is here}}
+    // expected-error at -1 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('auto' vs 'int')}}
+    // expected-note at -2 {{previous template template parameter is here}}
     template<int... Vi> struct B;
-    // new-note at -1 {{template parameter is declared here}}
+    // expected-note at -1 {{template parameter is declared here}}
     template struct A<B>;
-    // new-note at -1 {{
diff erent template parameters}}
+    // expected-note at -1 {{
diff erent template parameters}}
   } // namespace t3
 } // namespace nttp_auto
 

diff  --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 575055117b35fa..0fc3b1d3146984 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1204,8 +1204,8 @@ <h2 id="cxx17">C++17 implementation status</h2>
 <span id="p0522">(10): While this feature was initially implemented in Clang 4,
 it was not enabled by default prior to clang 19, but could be enabled with
 <tt>-frelaxed-template-template-args</tt>.
-Starting from Clang 19, the flag is deprecated and will be removed in a future
-version.
+In Clang 19, the flag was deprecated.
+In Clang 21, the flag was removed altogether.
 </span>
 </p>
 </details>


        


More information about the cfe-commits mailing list