Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[clang] Enable C++17 relaxed template template argument matching by default #89807

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -88,6 +93,17 @@ 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
(#GH36505).
- Implemented ``_BitInt`` literal suffixes ``__wb`` or ``__WB`` as a Clang extension with ``unsigned`` modifiers also allowed. (#GH85223).

C++17 Feature Support
Expand Down Expand Up @@ -164,6 +180,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
------------------

Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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";
}

Expand All @@ -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]";
}
Expand Down
16 changes: 10 additions & 6 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}

Expand Down Expand Up @@ -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.
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
mizvekov marked this conversation as resolved.
Show resolved Hide resolved
// Quick check for the common case:
// If P contains a parameter pack, then A [...] matches P if each of A's
Expand Down
107 changes: 101 additions & 6 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
mizvekov marked this conversation as resolved.
Show resolved Hide resolved
}
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: {
mizvekov marked this conversation as resolved.
Show resolved Hide resolved
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) {
Expand All @@ -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.
mizvekov marked this conversation as resolved.
Show resolved Hide resolved
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);
Expand Down Expand Up @@ -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
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
Original file line number Diff line number Diff line change
@@ -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();
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGenCXX/mangle-concept.cpp
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions clang/test/Driver/frelaxed-template-template-args.cpp
Original file line number Diff line number Diff line change
@@ -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]
6 changes: 3 additions & 3 deletions clang/test/Lexer/cxx-features.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading
Loading