https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/89807
>From 3f6e50edc7b4d4bf4781c71bd29f48224b62822d Mon Sep 17 00:00:00 2001 From: Matheus Izvekov <mizve...@gmail.com> Date: Tue, 9 Apr 2024 01:14:28 -0300 Subject: [PATCH] [clang] Enable C++17 relaxed template template argument matching by default In order to implement this as a DR and avoid breaking reasonable code that worked before P0522, this patch implements a provisional resolution for CWG2398: When deducing template template parameters against each other, and the argument side names a template specialization, instead of just deducing A, we instead deduce a synthesized template template parameter based on A, but with it's parameters using the template specialization's arguments as defaults. The driver flag is deprecated with a warning. With this patch, we finally mark C++17 support in clang as complete. Closes #55894 --- clang/docs/ReleaseNotes.rst | 18 +++ .../clang/Basic/DiagnosticDriverKinds.td | 2 +- clang/include/clang/Basic/LangOptions.def | 2 +- clang/include/clang/Driver/Options.td | 8 +- clang/lib/Driver/SanitizerArgs.cpp | 9 +- clang/lib/Driver/ToolChains/Clang.cpp | 16 ++- clang/lib/Sema/SemaTemplate.cpp | 3 - clang/lib/Sema/SemaTemplateDeduction.cpp | 107 +++++++++++++++- clang/test/CXX/drs/cwg2398.cpp | 115 ++++++++++++++++++ .../temp/temp.arg/temp.arg.template/p3-2a.cpp | 2 +- clang/test/CodeGenCXX/mangle-concept.cpp | 4 +- .../frelaxed-template-template-args.cpp | 5 + clang/test/Lexer/cxx-features.cpp | 6 +- clang/test/SemaTemplate/default-arguments.cpp | 7 +- .../instantiate-template-template-parm.cpp | 17 ++- clang/test/SemaTemplate/nested-template.cpp | 8 +- clang/test/SemaTemplate/temp_arg_template.cpp | 6 +- .../SemaTemplate/temp_arg_template_cxx1z.cpp | 2 +- clang/www/cxx_status.html | 18 ++- 19 files changed, 292 insertions(+), 63 deletions(-) create mode 100644 clang/test/CXX/drs/cwg2398.cpp create mode 100644 clang/test/Driver/frelaxed-template-template-args.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f5e5d3a2e6ea36..f525bdd73010cb 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -48,6 +48,11 @@ C++ Specific Potentially Breaking Changes - Clang now diagnoses function/variable templates that shadow their own template parameters, e.g. ``template<class T> void T();``. This error can be disabled via `-Wno-strict-primary-template-shadow` for compatibility with previous versions of clang. +- The behavior controlled by the `-frelaxed-template-template-args` flag is now + on by default, and the flag is deprecated. Until the flag is finally removed, + it's negative spelling can be used to obtain compatibility with previous + versions of clang. + ABI Changes in This Version --------------------------- - Fixed Microsoft name mangling of implicitly defined variables used for thread @@ -88,6 +93,16 @@ sections with improvements to Clang's support for those languages. C++ Language Changes -------------------- +- C++17 support is now completed, with the enablement of the + relaxed temlate template argument matching rules introduced in P0522, + which was retroactively applied as a defect report. + While the implementation already existed since Clang 4, it was turned off by + default, and was controlled with the `-frelaxed-template-template-args` flag. + In this release, we implement provisional wording for a core defect on + P0522 (CWG2398), which avoids the most serious compatibility issues caused + by it, allowing us to enable it by default in this release. + The flag is now deprecated, and will be removed in the next release, but can + still be used to turn it off and regain compatibility with previous versions. - Implemented ``_BitInt`` literal suffixes ``__wb`` or ``__WB`` as a Clang extension with ``unsigned`` modifiers also allowed. (#GH85223). C++20 Feature Support @@ -152,6 +167,9 @@ Resolutions to C++ Defect Reports - Clang now diagnoses declarative nested-name-specifiers with pack-index-specifiers. (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers <https://cplusplus.github.io/CWG/issues/2858.html>`_). +- P0522 implementation is enabled by default in all language versions, and + provisional wording for CWG2398 is implemented. + C Language Changes ------------------ diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index ed3fd9b1c4a55b..9781fcaa4ff5e9 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -435,7 +435,7 @@ def warn_drv_diagnostics_misexpect_requires_pgo : Warning< def warn_drv_clang_unsupported : Warning< "the clang compiler does not support '%0'">; def warn_drv_deprecated_arg : Warning< - "argument '%0' is deprecated, use '%1' instead">, InGroup<Deprecated>; + "argument '%0' is deprecated%select{|, use '%2' instead}1">, InGroup<Deprecated>; def warn_drv_deprecated_custom : Warning< "argument '%0' is deprecated, %1">, InGroup<Deprecated>; def warn_drv_assuming_mfloat_abi_is : Warning< diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 8ef6700ecdc78e..2a79e451f25f14 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -158,7 +158,7 @@ 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, 0, "C++17 relaxed matching of template template arguments") +LANGOPT(RelaxedTemplateTemplateArgs, 1, 1, "C++17 relaxed matching of template template arguments") LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library features") LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 4cb0b840df87b1..7f3e58b5342dfe 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3365,10 +3365,10 @@ defm application_extension : BoolFOption<"application-extension", "Restrict code to those available for App Extensions">, NegFlag<SetFalse>>; defm relaxed_template_template_args : BoolFOption<"relaxed-template-template-args", - LangOpts<"RelaxedTemplateTemplateArgs">, DefaultFalse, - PosFlag<SetTrue, [], [ClangOption, CC1Option], - "Enable C++17 relaxed template template argument matching">, - NegFlag<SetFalse>>; + LangOpts<"RelaxedTemplateTemplateArgs">, DefaultTrue, + PosFlag<SetTrue, [], [], "Enable">, + NegFlag<SetFalse, [], [CC1Option], "Disable">, + BothFlags<[], [ClangOption], " C++17 relaxed template template argument matching">>; defm sized_deallocation : BoolFOption<"sized-deallocation", LangOpts<"SizedDeallocation">, DefaultFalse, PosFlag<SetTrue, [], [ClangOption, CC1Option], diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 6a4f2548c0bffa..273f215ca94a88 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -797,7 +797,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, Arg->claim(); if (LegacySanitizeCoverage != 0 && DiagnoseErrors) { D.Diag(diag::warn_drv_deprecated_arg) - << Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard"; + << Arg->getAsString(Args) << /*hasReplacement=*/true + << "-fsanitize-coverage=trace-pc-guard"; } continue; } @@ -833,11 +834,11 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // enabled. if (CoverageFeatures & CoverageTraceBB) D.Diag(clang::diag::warn_drv_deprecated_arg) - << "-fsanitize-coverage=trace-bb" + << "-fsanitize-coverage=trace-bb" << /*hasReplacement=*/true << "-fsanitize-coverage=trace-pc-guard"; if (CoverageFeatures & Coverage8bitCounters) D.Diag(clang::diag::warn_drv_deprecated_arg) - << "-fsanitize-coverage=8bit-counters" + << "-fsanitize-coverage=8bit-counters" << /*hasReplacement=*/true << "-fsanitize-coverage=trace-pc-guard"; } @@ -849,7 +850,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, if ((CoverageFeatures & InsertionPointTypes) && !(CoverageFeatures & InstrumentationTypes) && DiagnoseErrors) { D.Diag(clang::diag::warn_drv_deprecated_arg) - << "-fsanitize-coverage=[func|bb|edge]" + << "-fsanitize-coverage=[func|bb|edge]" << /*hasReplacement=*/true << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc],[" "control-flow]"; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 651a2b5aac368b..42e77b62c277ff 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6529,7 +6529,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_global_new_delete_hidden)) { D.Diag(diag::warn_drv_deprecated_arg) - << A->getAsString(Args) + << A->getAsString(Args) << /*hasReplacement=*/true << "-fvisibility-global-new-delete=force-hidden"; } @@ -7256,11 +7256,15 @@ 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 off by default, as it is a severe - // breaking change until a corresponding change to template partial ordering - // is provided. - Args.addOptInFlag(CmdArgs, options::OPT_frelaxed_template_template_args, - options::OPT_fno_relaxed_template_template_args); + // -frelaxed-template-template-args is deprecated. + if (Arg *A = + Args.getLastArg(options::OPT_frelaxed_template_template_args, + options::OPT_fno_relaxed_template_template_args)) { + D.Diag(diag::warn_drv_deprecated_arg) + << A->getAsString(Args) << /*hasReplacement=*/false; + if (A->getOption().matches(options::OPT_fno_relaxed_template_template_args)) + CmdArgs.push_back("-fno-relaxed-template-template-args"); + } // -fsized-deallocation is off by default, as it is an ABI-breaking change for // most platforms. diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index bbcb7c33a98579..447e3e2f3a35b5 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -8343,9 +8343,6 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, // 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. - // FIXME: We should enable RelaxedTemplateTemplateArgs by default as it is a - // defect report resolution from C++17 and shouldn't be introduced by - // concepts. if (getLangOpts().RelaxedTemplateTemplateArgs) { // Quick check for the common case: // If P contains a parameter pack, then A [...] matches P if each of A's diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index c3815bca038554..c20a7da64bda60 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -507,10 +507,70 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, DeducedTemplateArgument(New), T, Info, Deduced); } +/// Create a shallow copy of a given template parameter declaration, with +/// empty source locations and using the given TemplateArgument as it's +/// default argument. +/// +/// \returns The new template parameter declaration. +static NamedDecl *getTemplateParameterWithDefault(Sema &S, NamedDecl *A, + TemplateArgument Default) { + switch (A->getKind()) { + case Decl::TemplateTypeParm: { + auto *T = cast<TemplateTypeParmDecl>(A); + // FIXME: A TemplateTypeParmDecl's DefaultArgument can't hold a full + // TemplateArgument, so there is currently no way to specify a pack as a + // default argument for these. + if (T->isParameterPack()) + return A; + auto *R = TemplateTypeParmDecl::Create( + S.Context, A->getDeclContext(), SourceLocation(), SourceLocation(), + T->getDepth(), T->getIndex(), T->getIdentifier(), + T->wasDeclaredWithTypename(), /*ParameterPack=*/false, + T->hasTypeConstraint()); + R->setDefaultArgument( + S.Context.getTrivialTypeSourceInfo(Default.getAsType())); + if (R->hasTypeConstraint()) { + auto *C = R->getTypeConstraint(); + R->setTypeConstraint(C->getConceptReference(), + C->getImmediatelyDeclaredConstraint()); + } + return R; + } + case Decl::NonTypeTemplateParm: { + auto *T = cast<NonTypeTemplateParmDecl>(A); + // FIXME: Ditto, as above for TemplateTypeParm case. + if (T->isParameterPack()) + return A; + auto *R = NonTypeTemplateParmDecl::Create( + S.Context, A->getDeclContext(), SourceLocation(), SourceLocation(), + T->getDepth(), T->getIndex(), T->getIdentifier(), T->getType(), + /*ParameterPack=*/false, T->getTypeSourceInfo()); + R->setDefaultArgument(Default.getAsExpr()); + if (auto *PTC = T->getPlaceholderTypeConstraint()) + R->setPlaceholderTypeConstraint(PTC); + return R; + } + case Decl::TemplateTemplateParm: { + auto *T = cast<TemplateTemplateParmDecl>(A); + auto *R = TemplateTemplateParmDecl::Create( + S.Context, A->getDeclContext(), SourceLocation(), T->getDepth(), + T->getIndex(), T->isParameterPack(), T->getIdentifier(), + T->wasDeclaredWithTypename(), T->getTemplateParameters()); + R->setDefaultArgument( + S.Context, + S.getTrivialTemplateArgumentLoc(Default, QualType(), SourceLocation())); + return R; + } + default: + llvm_unreachable("Unexpected Decl Kind"); + } +} + static TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, TemplateName Param, TemplateName Arg, TemplateDeductionInfo &Info, + ArrayRef<TemplateArgument> DefaultArguments, SmallVectorImpl<DeducedTemplateArgument> &Deduced) { TemplateDecl *ParamDecl = Param.getAsTemplateDecl(); if (!ParamDecl) { @@ -519,13 +579,45 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, return TemplateDeductionResult::Success; } - if (TemplateTemplateParmDecl *TempParam - = dyn_cast<TemplateTemplateParmDecl>(ParamDecl)) { + if (auto *TempParam = dyn_cast<TemplateTemplateParmDecl>(ParamDecl)) { // If we're not deducing at this depth, there's nothing to deduce. if (TempParam->getDepth() != Info.getDeducedDepth()) return TemplateDeductionResult::Success; - DeducedTemplateArgument NewDeduced(S.Context.getCanonicalTemplateName(Arg)); + auto NewDeduced = DeducedTemplateArgument(Arg); + // Provisional resolution for CWG2398: If Arg is also a template template + // param, and it names a template specialization, then we deduce a + // synthesized template template parameter based on A, but using the TS's + // arguments as defaults. + if (auto *TempArg = dyn_cast_or_null<TemplateTemplateParmDecl>( + Arg.getAsTemplateDecl())) { + assert(Arg.getKind() == TemplateName::Template); + assert(!TempArg->isExpandedParameterPack()); + + TemplateParameterList *As = TempArg->getTemplateParameters(); + if (DefaultArguments.size() != 0) { + assert(DefaultArguments.size() <= As->size()); + SmallVector<NamedDecl *, 4> Params(As->size()); + for (unsigned I = 0; I < DefaultArguments.size(); ++I) + Params[I] = getTemplateParameterWithDefault(S, As->getParam(I), + DefaultArguments[I]); + for (unsigned I = DefaultArguments.size(); I < As->size(); ++I) + Params[I] = As->getParam(I); + // FIXME: We could unique these, and also the parameters, but we don't + // expect programs to contain a large enough amount of these deductions + // for that to be worthwhile. + auto *TPL = TemplateParameterList::Create( + S.Context, SourceLocation(), SourceLocation(), Params, + SourceLocation(), As->getRequiresClause()); + NewDeduced = DeducedTemplateArgument( + TemplateName(TemplateTemplateParmDecl::Create( + S.Context, TempArg->getDeclContext(), SourceLocation(), + TempArg->getDepth(), TempArg->getPosition(), + TempArg->isParameterPack(), TempArg->getIdentifier(), + TempArg->wasDeclaredWithTypename(), TPL))); + } + } + DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, Deduced[TempParam->getIndex()], NewDeduced); @@ -604,7 +696,8 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, // Perform template argument deduction for the template name. if (auto Result = - DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, Deduced); + DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, + SA->template_arguments(), Deduced); Result != TemplateDeductionResult::Success) return Result; // Perform template argument deduction on each template @@ -630,7 +723,8 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, // Perform template argument deduction for the template name. if (auto Result = DeduceTemplateArguments( S, TemplateParams, TP->getTemplateName(), - TemplateName(SA->getSpecializedTemplate()), Info, Deduced); + TemplateName(SA->getSpecializedTemplate()), Info, + SA->getTemplateArgs().asArray(), Deduced); Result != TemplateDeductionResult::Success) return Result; @@ -2323,7 +2417,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, case TemplateArgument::Template: if (A.getKind() == TemplateArgument::Template) return DeduceTemplateArguments(S, TemplateParams, P.getAsTemplate(), - A.getAsTemplate(), Info, Deduced); + A.getAsTemplate(), Info, + /*DefaultArguments=*/{}, Deduced); Info.FirstArg = P; Info.SecondArg = A; return TemplateDeductionResult::NonDeducedMismatch; diff --git a/clang/test/CXX/drs/cwg2398.cpp b/clang/test/CXX/drs/cwg2398.cpp new file mode 100644 index 00000000000000..bda7143d2cc5e1 --- /dev/null +++ b/clang/test/CXX/drs/cwg2398.cpp @@ -0,0 +1,115 @@ +// 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 + +namespace issue1 { + template<class T, class U = T> class B {}; + template<template<class> class P, class T> void f(P<T>); + // new-note@-1 {{deduced type 'B<[...], (default) int>' of 1st parameter does not match adjusted type 'B<[...], float>' of argument [with P = issue1::B, T = int]}} + // old-note@-2 2{{template template argument has different template parameters}} + + void g() { + f(B<int>()); // old-error {{no matching function for call}} + f(B<int,float>()); // expected-error {{no matching function for call}} + } +} // namespace issue1 + +namespace issue2 { + template<typename> struct match; + + template<template<typename> class t,typename T> struct match<t<T>>; + + template<template<typename,typename> class t,typename T0,typename T1> + struct match<t<T0,T1>> {}; + + template<typename,typename = void> struct other {}; + template struct match<other<void,void>>; +} // namespace issue2 + +namespace type { + template<class T1, class T2 = float> struct A {}; + + template<class T3> struct B; + template<template<class T4 > class TT1, class T5 > struct B<TT1<T5 >> ; + template<template<class T6, class T7> class TT2, class T8, class T9> struct B<TT2<T8, T9>> {}; + template struct B<A<int>>; +} // namespace type + +namespace value { + template<class T1, int V1 = 1> struct A {}; + + template<class T2> struct B; + template<template<class T3 > class TT1, class T4 > struct B<TT1<T4 >> ; + template<template<class T5, int V2> class TT2, class T6, int V3> struct B<TT2<T6, V3>> {}; + template struct B<A<int>>; +} // namespace value + +namespace templ { + template <class T1> struct A {}; + + template<class T2, template <class T3> class T4 = A> struct B {}; + + template<class T5> struct C; + + template<template<class T6> class TT1, class T7> struct C<TT1<T7>>; + + template<template<class T8, template <class T9> class> class TT2, + class T10, template <class T11> class TT3> + struct C<TT2<T10, TT3>> {}; + + template struct C<B<int>>; +} // namespace templ + +namespace type_pack { + template<class T1, class T2 = float> struct A {}; + + template<class T3> struct B; + + template<template<class T4 > class TT1, class T5 > struct B<TT1<T5 >>; + // new-note@-1 {{template is declared here}} + template<template<class T6, class ...T7s> class TT2, class T8, class ...T9s> struct B<TT2<T8, T9s...>>; + // old-note@-1 {{template is declared here}} + + template struct B<A<int>>; + // expected-error@-1 {{explicit instantiation of undefined template}} +} // namespace type_pack + +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@-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@-1 {{partial specialization matches}} + // old-note@-2 {{template is declared here}} + + template <class T7, class T8 = T7> struct B { using type = int; }; + + template struct A<B<int>, int>; + // new-error@-1 {{ambiguous partial specializations}} + // old-error@-2 {{explicit instantiation of undefined template}} +} // namespace gcc_issue + +namespace ttp_defaults { + template <template <class T1> class TT1> struct A {}; + // old-note@-1 2{{previous template template parameter}} + + template <template <class T2> class TT2> void f(A<TT2>); + // new-note@-1 {{explicit instantiation candidate}} + // old-note@-2 {{invalid explicitly-specified argument for template parameter 'TT2'}} + + // 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@-1 {{explicit instantiation candidate}} + // old-error@-2 {{template template argument has different template parameters}} + // old-note@-3 {{too many template parameters}} + + template <class T5, class T6 = int> struct B; + // old-note@-1 {{too many template parameters}} + + template void f<B>(A<B>); + // new-error@-1 {{partial ordering for explicit instantiation of 'f' is ambiguous}} + // old-error@-2 {{template template argument has different template parameters}} + // old-error@-3 {{explicit instantiation of 'f' does not refer to a function template}} +} // namespace ttp_defaults diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp index f586069638614b..342ffba53dbfaf 100644 --- a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp +++ b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a -frelaxed-template-template-args -verify %s +// RUN: %clang_cc1 -std=c++2a -verify %s template<typename T> concept C = T::f(); // #C template<typename T> concept D = C<T> && T::g(); diff --git a/clang/test/CodeGenCXX/mangle-concept.cpp b/clang/test/CodeGenCXX/mangle-concept.cpp index bbd2cf6555e3ec..e9c46d87635abb 100644 --- a/clang/test/CodeGenCXX/mangle-concept.cpp +++ b/clang/test/CodeGenCXX/mangle-concept.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -verify -frelaxed-template-template-args -std=c++20 -emit-llvm -triple %itanium_abi_triple -o - %s -fclang-abi-compat=latest | FileCheck %s -// RUN: %clang_cc1 -verify -frelaxed-template-template-args -std=c++20 -emit-llvm -triple %itanium_abi_triple -o - %s -fclang-abi-compat=16 | FileCheck %s --check-prefix=CLANG16 +// RUN: %clang_cc1 -verify -std=c++20 -emit-llvm -triple %itanium_abi_triple -o - %s -fclang-abi-compat=latest | FileCheck %s +// RUN: %clang_cc1 -verify -std=c++20 -emit-llvm -triple %itanium_abi_triple -o - %s -fclang-abi-compat=16 | FileCheck %s --check-prefix=CLANG16 // expected-no-diagnostics namespace test1 { diff --git a/clang/test/Driver/frelaxed-template-template-args.cpp b/clang/test/Driver/frelaxed-template-template-args.cpp new file mode 100644 index 00000000000000..dd6265ba8375eb --- /dev/null +++ b/clang/test/Driver/frelaxed-template-template-args.cpp @@ -0,0 +1,5 @@ +// 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 + +// CHECK-ON: warning: argument '-frelaxed-template-template-args' is deprecated [-Wdeprecated] +// CHECK-OFF: warning: argument '-fno-relaxed-template-template-args' is deprecated [-Wdeprecated] diff --git a/clang/test/Lexer/cxx-features.cpp b/clang/test/Lexer/cxx-features.cpp index baaa9d4434e9b7..4f1fe70d1191c1 100644 --- a/clang/test/Lexer/cxx-features.cpp +++ b/clang/test/Lexer/cxx-features.cpp @@ -7,7 +7,7 @@ // RUN: %clang_cc1 -std=c++2c -fcxx-exceptions -fsized-deallocation -verify %s // -// RUN: %clang_cc1 -std=c++17 -fcxx-exceptions -fsized-deallocation -frelaxed-template-template-args -DRELAXED_TEMPLATE_TEMPLATE_ARGS=1 -verify %s +// RUN: %clang_cc1 -std=c++17 -fcxx-exceptions -fsized-deallocation -fno-relaxed-template-template-args -DNO_RELAXED_TEMPLATE_TEMPLATE_ARGS=1 -verify %s // RUN: %clang_cc1 -std=c++17 -fcxx-exceptions -fsized-deallocation -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 -fsized-deallocation // RUN: %clang_cc1 -std=c++14 -fchar8_t -DNO_EXCEPTIONS -DCHAR8_T -verify -fsized-deallocation %s @@ -231,8 +231,8 @@ #error "wrong value for __cpp_nontype_template_args" #endif -#if defined(RELAXED_TEMPLATE_TEMPLATE_ARGS) \ - ? check(template_template_args, 0, 0, 0, 201611, 201611, 201611, 201611) \ +#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) #error "wrong value for __cpp_template_template_args" #endif diff --git a/clang/test/SemaTemplate/default-arguments.cpp b/clang/test/SemaTemplate/default-arguments.cpp index a850d273ccba51..d5d9687cc90f49 100644 --- a/clang/test/SemaTemplate/default-arguments.cpp +++ b/clang/test/SemaTemplate/default-arguments.cpp @@ -112,15 +112,14 @@ template<typename T, template<typename> class X = T::template apply> int array4[is_same<X4<add_pointer>, X4<add_pointer, add_pointer::apply> >::value? 1 : -1]; -template<int> struct X5 {}; // expected-note{{has a different type 'int'}} +template<int> struct X5 {}; template<long> struct X5b {}; template<typename T, - template<T> class B = X5> // expected-error{{template template argument has different}} \ - // expected-note{{previous non-type template parameter}} + template<T> class B = X5> struct X6 {}; X6<int> x6a; -X6<long> x6b; // expected-note{{while checking a default template argument}} +X6<long> x6b; X6<long, X5b> x6c; diff --git a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp index a70c7e8b081a41..39aeeb1c1a6a32 100644 --- a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp +++ b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp @@ -20,30 +20,29 @@ apply<add_reference, int>::type ir = i; apply<add_reference, float>::type fr = i; // expected-error{{non-const lvalue reference to type 'float' cannot bind to a value of unrelated type 'int'}} // Template template parameters -template<int> struct B; // expected-note{{has a different type 'int'}} +template<int> struct B; -template<typename T, - template<T Value> class X> // expected-error{{cannot have type 'float'}} \ - // expected-note{{with type 'long'}} +template<typename T, + template<T Value> class X> // expected-error{{cannot have type 'float'}} struct X0 { }; X0<int, B> x0b1; X0<float, B> x0b2; // expected-note{{while substituting}} -X0<long, B> x0b3; // expected-error{{template template argument has different template parameters}} +X0<long, B> x0b3; -template<template<int V> class TT> // expected-note{{parameter with type 'int'}} +template<template<int V> class TT> struct X1 { }; template<typename T, template<T V> class TT> struct X2 { - X1<TT> x1; // expected-error{{has different template parameters}} + X1<TT> x1; }; template<int V> struct X3i { }; -template<long V> struct X3l { }; // expected-note{{different type 'long'}} +template<long V> struct X3l { }; X2<int, X3i> x2okay; -X2<long, X3l> x2bad; // expected-note{{instantiation}} +X2<long, X3l> x2okay2; template <typename T, template <T, T> class TT, class R = TT<1, 2> > struct Comp { diff --git a/clang/test/SemaTemplate/nested-template.cpp b/clang/test/SemaTemplate/nested-template.cpp index efbde2076b9fa1..5bd388d4dff3d7 100644 --- a/clang/test/SemaTemplate/nested-template.cpp +++ b/clang/test/SemaTemplate/nested-template.cpp @@ -112,18 +112,16 @@ template struct X1<int>::B<bool>; // Template template parameters template<typename T> struct X2 { - template<template<class U, T Value> class> // expected-error{{cannot have type 'float'}} \ - // expected-note{{previous non-type template}} + template<template<class U, T Value> class> // expected-error{{cannot have type 'float'}} struct Inner { }; }; -template<typename T, - int Value> // expected-note{{template non-type parameter}} +template<typename T, int Value> struct X2_arg; X2<int>::Inner<X2_arg> x2i1; X2<float> x2a; // expected-note{{instantiation}} -X2<long>::Inner<X2_arg> x2i3; // expected-error{{template template argument has different}} +X2<long>::Inner<X2_arg> x2i3; namespace PR10896 { template<typename TN> diff --git a/clang/test/SemaTemplate/temp_arg_template.cpp b/clang/test/SemaTemplate/temp_arg_template.cpp index 3c2697329212e9..a7236669276aa3 100644 --- a/clang/test/SemaTemplate/temp_arg_template.cpp +++ b/clang/test/SemaTemplate/temp_arg_template.cpp @@ -5,11 +5,11 @@ template<template<typename T> class X> struct A; // expected-note 2{{previous te template<template<typename T, int I> class X> struct B; // expected-note{{previous template template parameter is here}} -template<template<int I> class X> struct C; // expected-note 2{{previous non-type template parameter with type 'int' is here}} +template<template<int I> class X> struct C; // expected-note {{previous non-type template parameter with type 'int' is here}} template<class> struct X; // expected-note{{too few template parameters in template template argument}} template<int N> struct Y; // expected-note{{template parameter has a different kind in template argument}} -template<long N> struct Ylong; // expected-note{{template non-type parameter has a different type 'long' in template argument}} +template<long N> struct Ylong; template<const int &N> struct Yref; // expected-note{{template non-type parameter has a different type 'const int &' in template argument}} namespace N { @@ -26,7 +26,7 @@ A<Y> *a4; // expected-error{{template template argument has different template p A<TooMany> *a5; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} B<X> *a6; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} C<Y> *a7; -C<Ylong> *a8; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} +C<Ylong> *a8; C<Yref> *a9; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} template<typename T> void f(int); diff --git a/clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp index 03ef78f8cf14e1..372a00efc601e4 100644 --- a/clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp +++ b/clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z -frelaxed-template-template-args %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s // expected-note@temp_arg_template_cxx1z.cpp:* 1+{{}} diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index c233171e63c811..d7401b5cda269f 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -916,7 +916,7 @@ <h2 id="cxx17">C++17 implementation status</h2> You can use Clang in C++17 mode with the <code>-std=c++17</code> option (use <code>-std=c++1z</code> in Clang 4 and earlier).</p> -<details open> +<details> <summary>List of features and minimum Clang version with support</summary> <table width="689" border="1" cellspacing="0"> @@ -1133,8 +1133,8 @@ <h2 id="cxx17">C++17 implementation status</h2> <!-- Issaquah 2016 papers --> <tr> <td>Matching template template parameters to compatible arguments</td> - <td><a href="https://wg21.link/p0522r0">P0522R0</a></td> - <td class="partial" align="center">Partial <a href="#p0522">(10)</a></td> + <td><a href="https://wg21.link/p0522r0">P0522R0</a> (<a href="#dr">DR</a>)</td> + <td class="full" align="center">Clang 19 <a href="#p0522">(10)</a></td> </tr> <tr> <td>Removing deprecated dynamic exception specifications</td> @@ -1162,13 +1162,11 @@ <h2 id="cxx17">C++17 implementation status</h2> reverse construction order in that ABI. This is not fully supported during constant expression evaluation until Clang 12. </span><br> -<span id="p0522">(10): Despite being the resolution to a Defect Report, this -feature is disabled by default in all language versions, and can be enabled -explicitly with the flag <tt>-frelaxed-template-template-args</tt> in Clang 4 -onwards. -The change to the standard lacks a corresponding change for template partial -ordering, resulting in ambiguity errors for reasonable and previously-valid -code. This issue is expected to be rectified soon. +<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. </span> </p> </details> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits