diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -355,7 +355,7 @@ 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; + "argument '%0' is deprecated%select{|, use '%2' instead}1">, InGroup; def warn_drv_assuming_mfloat_abi_is : Warning< "unknown platform, assuming -mfloat-abi=%0">; def warn_ignoring_ftabstop_value : Warning< diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -149,7 +149,6 @@ LANGOPT(GNUAsm , 1, 1, "GNU-style inline assembly") LANGOPT(Coroutines , 1, 0, "C++20 coroutines") LANGOPT(DllExportInlines , 1, 1, "dllexported classes dllexport inline methods") -LANGOPT(RelaxedTemplateTemplateArgs, 1, 0, "C++17 relaxed matching of template template arguments") LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2334,10 +2334,8 @@ LangOpts<"AppExt">, DefaultFalse, PosFlag, NegFlag>; -defm relaxed_template_template_args : BoolFOption<"relaxed-template-template-args", - LangOpts<"RelaxedTemplateTemplateArgs">, DefaultFalse, - PosFlag, - NegFlag>; +def frelaxed_template_template_args : Flag<["-"], "frelaxed-template-template-args">, Flags<[]>; +def fno_relaxed_template_template_args : Flag<["-"], "fno-relaxed-template-template-args">, Flags<[]>; defm sized_deallocation : BoolFOption<"sized-deallocation", LangOpts<"SizedDeallocation">, DefaultFalse, PosFlag, diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -683,7 +683,8 @@ Arg->claim(); if (LegacySanitizeCoverage != 0) { D.Diag(diag::warn_drv_deprecated_arg) - << Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard"; + << Arg->getAsString(Args) << true + << "-fsanitize-coverage=trace-pc-guard"; } continue; } @@ -718,11 +719,11 @@ // enabled. if (CoverageFeatures & CoverageTraceBB) D.Diag(clang::diag::warn_drv_deprecated_arg) - << "-fsanitize-coverage=trace-bb" + << "-fsanitize-coverage=trace-bb" << 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" << true << "-fsanitize-coverage=trace-pc-guard"; int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge; @@ -732,7 +733,7 @@ if ((CoverageFeatures & InsertionPointTypes) && !(CoverageFeatures & InstrumentationTypes)) { D.Diag(clang::diag::warn_drv_deprecated_arg) - << "-fsanitize-coverage=[func|bb|edge]" + << "-fsanitize-coverage=[func|bb|edge]" << true << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]"; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6391,12 +6391,10 @@ options::OPT_fno_assume_sane_operator_new)) CmdArgs.push_back("-fno-assume-sane-operator-new"); - // -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. - if (Args.hasFlag(options::OPT_frelaxed_template_template_args, - options::OPT_fno_relaxed_template_template_args, false)) - CmdArgs.push_back("-frelaxed-template-template-args"); + // -frelaxed-template-template-args is deprecated, with no effect. + 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) << false; // -fsized-deallocation is off by default, as it is an ABI-breaking change for // most platforms. diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1890,12 +1890,12 @@ // Emit warnings for legacy options even if they are overridden. if (Args.hasArg(options::OPT_mno_code_object_v3_legacy)) - D.Diag(diag::warn_drv_deprecated_arg) << "-mno-code-object-v3" - << "-mcode-object-version=2"; + D.Diag(diag::warn_drv_deprecated_arg) + << "-mno-code-object-v3" << true << "-mcode-object-version=2"; if (Args.hasArg(options::OPT_mcode_object_v3_legacy)) - D.Diag(diag::warn_drv_deprecated_arg) << "-mcode-object-v3" - << "-mcode-object-version=3"; + D.Diag(diag::warn_drv_deprecated_arg) + << "-mcode-object-v3" << true << "-mcode-object-version=3"; if (auto *CodeObjArg = getAMDGPUCodeObjectArgument(D, Args)) { if (CodeObjArg->getOption().getID() == diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -589,8 +589,8 @@ } 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 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -7407,56 +7407,50 @@ // 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 - // template parameters matches the corresponding template parameter in - // the template-parameter-list of P. - if (TemplateParameterListsAreEqual( - Template->getTemplateParameters(), Params, false, - TPL_TemplateTemplateArgumentMatch, Arg.getLocation()) && - // If the argument has no associated constraints, then the parameter is - // definitely at least as specialized as the argument. - // Otherwise - we need a more thorough check. - !Template->hasAssociatedConstraints()) - return false; + // Quick check for the common case: + // If P contains a parameter pack, then A [...] matches P if each of A's + // template parameters matches the corresponding template parameter in + // the template-parameter-list of P. + if (TemplateParameterListsAreEqual(Template->getTemplateParameters(), Params, + false, TPL_TemplateTemplateArgumentMatch, + Arg.getLocation()) && + // If the argument has no associated constraints, then the parameter is + // definitely at least as specialized as the argument. + // Otherwise - we need a more thorough check. + !Template->hasAssociatedConstraints()) + return false; - if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template, - Arg.getLocation())) { - // C++2a[temp.func.order]p2 - // [...] If both deductions succeed, the partial ordering selects the - // more constrained template as described by the rules in - // [temp.constr.order]. - SmallVector ParamsAC, TemplateAC; - Params->getAssociatedConstraints(ParamsAC); - // C++2a[temp.arg.template]p3 - // [...] In this comparison, if P is unconstrained, the constraints on A - // are not considered. - if (ParamsAC.empty()) - return false; - Template->getAssociatedConstraints(TemplateAC); - bool IsParamAtLeastAsConstrained; - if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, - IsParamAtLeastAsConstrained)) - return true; - if (!IsParamAtLeastAsConstrained) { - Diag(Arg.getLocation(), - diag::err_template_template_parameter_not_at_least_as_constrained) - << Template << Param << Arg.getSourceRange(); - Diag(Param->getLocation(), diag::note_entity_declared_at) << Param; - Diag(Template->getLocation(), diag::note_entity_declared_at) - << Template; - MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Param, ParamsAC, Template, - TemplateAC); - return true; - } + if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template, + Arg.getLocation())) { + // C++2a[temp.func.order]p2 + // [...] If both deductions succeed, the partial ordering selects the + // more constrained template as described by the rules in + // [temp.constr.order]. + SmallVector ParamsAC, TemplateAC; + Params->getAssociatedConstraints(ParamsAC); + // C++2a[temp.arg.template]p3 + // [...] In this comparison, if P is unconstrained, the constraints on A + // are not considered. + if (ParamsAC.empty()) return false; + Template->getAssociatedConstraints(TemplateAC); + bool IsParamAtLeastAsConstrained; + if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, + IsParamAtLeastAsConstrained)) + return true; + if (!IsParamAtLeastAsConstrained) { + Diag(Arg.getLocation(), + diag::err_template_template_parameter_not_at_least_as_constrained) + << Template << Param << Arg.getSourceRange(); + Diag(Param->getLocation(), diag::note_entity_declared_at) << Param; + Diag(Template->getLocation(), diag::note_entity_declared_at) << Template; + MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Param, ParamsAC, Template, + TemplateAC); + return true; } - // FIXME: Produce better diagnostics for deduction failures. + return false; } + // FIXME: Produce better diagnostics for deduction failures. return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), Params, diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -5514,33 +5514,52 @@ /// neither partial specialization is more specialized, returns NULL. ClassTemplatePartialSpecializationDecl * Sema::getMoreSpecializedPartialSpecialization( - ClassTemplatePartialSpecializationDecl *PS1, - ClassTemplatePartialSpecializationDecl *PS2, - SourceLocation Loc) { - QualType PT1 = PS1->getInjectedSpecializationType(); - QualType PT2 = PS2->getInjectedSpecializationType(); - - TemplateDeductionInfo Info(Loc); - bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info); - bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); - - if (!Better1 && !Better2) - return nullptr; - if (Better1 && Better2) { + ClassTemplatePartialSpecializationDecl *PS1, + ClassTemplatePartialSpecializationDecl *PS2, SourceLocation Loc) { + { + QualType PT1 = PS1->getInjectedSpecializationType(), + PT2 = PS2->getInjectedSpecializationType(); + TemplateDeductionInfo Info(Loc); + bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info), + Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); + if (Better1 != Better2) + return Better1 ? PS1 : PS2; + } + { llvm::SmallVector AC1, AC2; PS1->getAssociatedConstraints(AC1); PS2->getAssociatedConstraints(AC2); - bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1)) - return nullptr; - if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2)) + bool Better1, Better2; + if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, Better1)) return nullptr; - if (AtLeastAsConstrained1 == AtLeastAsConstrained2) + if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, Better2)) return nullptr; - return AtLeastAsConstrained1 ? PS1 : PS2; + if (Better1 != Better2) + return Better1 ? PS1 : PS2; } - - return Better1 ? PS1 : PS2; + { + // This is a workaround for the ambiguity issues created by + // P0522, which is the resolution of CWG 150. + // Pick as the more specialized partial specialization the one + // which has the first template argument of template specialization type + // with a smaller number of arguments. + auto As1 = PS1->getTemplateArgs().asArray(), + As2 = PS2->getTemplateArgs().asArray(); + assert(As1.size() == As2.size()); + for (int I = 0; I < As1.size(); ++I) { + const auto &A1 = As1[I], &A2 = As2[I]; + if (A1.getKind() == TemplateArgument::ArgKind::Type && + A2.getKind() == TemplateArgument::ArgKind::Type) { + const auto *AT1 = dyn_cast( + A1.getAsType()->getCanonicalTypeInternal()), + *AT2 = dyn_cast( + A2.getAsType()->getCanonicalTypeInternal()); + if (AT1 && AT2 && AT1->getNumArgs() != AT2->getNumArgs()) + return AT1->getNumArgs() < AT2->getNumArgs() ? PS1 : PS2; + } + } + } + return nullptr; } bool Sema::isMoreSpecializedThanPrimary( 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 --- 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 concept C = T::f(); // expected-note@-1{{similar constraint}} diff --git a/clang/test/Driver/frelaxed-template-template-args.cpp b/clang/test/Driver/frelaxed-template-template-args.cpp new file mode 100644 --- /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 --- a/clang/test/Lexer/cxx-features.cpp +++ b/clang/test/Lexer/cxx-features.cpp @@ -5,7 +5,6 @@ // RUN: %clang_cc1 -std=c++20 -fcxx-exceptions -fsized-deallocation -verify %s // RUN: %clang_cc1 -std=c++2b -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 -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 -fcoroutines-ts -DNO_EXCEPTIONS -DCOROUTINES -verify -fsized-deallocation %s @@ -195,9 +194,7 @@ #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) \ - : check(template_template_args, 0, 0, 0, 0, 0, 0) +#if check(template_template_args, 201611, 201611, 201611, 201611, 201611, 201611) #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 --- a/clang/test/SemaTemplate/default-arguments.cpp +++ b/clang/test/SemaTemplate/default-arguments.cpp @@ -112,15 +112,14 @@ int array4[is_same, X4 >::value? 1 : -1]; -template struct X5 {}; // expected-note{{has a different type 'int'}} +template struct X5 {}; template struct X5b {}; template class B = X5> // expected-error{{template template argument has different}} \ - // expected-note{{previous non-type template parameter}} + template class B = X5> struct X6 {}; X6 x6a; -X6 x6b; // expected-note{{while checking a default template argument}} +X6 x6b; X6 x6c; diff --git a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp --- a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp +++ b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp @@ -20,30 +20,29 @@ apply::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 struct B; // expected-note{{has a different type 'int'}} +template struct B; template class X> // expected-error{{cannot have type 'float'}} \ - // expected-note{{with type 'long'}} + template class X> // expected-error{{cannot have type 'float'}} struct X0 { }; X0 x0b1; X0 x0b2; // expected-note{{while substituting}} -X0 x0b3; // expected-error{{template template argument has different template parameters}} +X0 x0b3; -template class TT> // expected-note{{parameter with type 'int'}} +template class TT> struct X1 { }; template class TT> struct X2 { - X1 x1; // expected-error{{has different template parameters}} + X1 x1; }; template struct X3i { }; -template struct X3l { }; // expected-note{{different type 'long'}} +template struct X3l { }; X2 x2okay; -X2 x2bad; // expected-note{{instantiation}} +X2 x2bad; template 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 --- a/clang/test/SemaTemplate/nested-template.cpp +++ b/clang/test/SemaTemplate/nested-template.cpp @@ -112,18 +112,16 @@ // Template template parameters template struct X2 { - template class> // expected-error{{cannot have type 'float'}} \ - // expected-note{{previous non-type template}} + template class> // expected-error{{cannot have type 'float'}} struct Inner { }; }; -template // expected-note{{template non-type parameter}} +template struct X2_arg; X2::Inner x2i1; X2 x2a; // expected-note{{instantiation}} -X2::Inner x2i3; // expected-error{{template template argument has different}} +X2::Inner x2i3; namespace PR10896 { template diff --git a/clang/test/SemaTemplate/temp_arg_template.cpp b/clang/test/SemaTemplate/temp_arg_template.cpp --- a/clang/test/SemaTemplate/temp_arg_template.cpp +++ b/clang/test/SemaTemplate/temp_arg_template.cpp @@ -6,11 +6,11 @@ template class X> struct B; // expected-note{{previous template template parameter is here}} -template class X> struct C; // expected-note 2{{previous non-type template parameter with type 'int' is here}} +template class X> struct C; // expected-note {{previous non-type template parameter with type 'int' is here}} template struct X; // expected-note{{too few template parameters in template template argument}} template struct Y; // expected-note{{template parameter has a different kind in template argument}} -template struct Ylong; // expected-note{{template non-type parameter has a different type 'long' in template argument}} +template struct Ylong; template struct Yref; // expected-note{{template non-type parameter has a different type 'const int &' in template argument}} namespace N { @@ -27,7 +27,7 @@ A *a5; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} B *a6; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} C *a7; -C *a8; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} +C *a8; C *a9; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} template void f(int); diff --git a/clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_template_cxx1z.cpp --- 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 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -596,7 +596,7 @@

You can use Clang in C++17 mode with the -std=c++17 option (use -std=c++1z in Clang 4 and earlier).

-
+
List of features and minimum Clang version with support @@ -813,8 +813,8 @@ - - + + @@ -842,13 +842,10 @@ reverse construction order in that ABI. This is not fully supported during constant expression evaluation until Clang 12.
-(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 -frelaxed-template-template-args 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. +(10): Prior to Clang 14, this feature is not enabled by +default, but can be enabled with -frelaxed-template-template-args. +Starting from Clang 14, the flag is deprecated and will be removed in a future +version.

Matching template template parameters to compatible argumentsP0522R0Partial (10)P0522R0 (DR)Clang 4 (10)
Removing deprecated dynamic exception specifications