Skip to content

Commit 0c7d46a

Browse files
authored
[Clang] Correctly construct template arguments for template template parameters (#76811)
This fixes the bug introduced by 6db007a. We construct placeholder template arguments for template-template parameters to avoid mismatching argument substitution since they have different depths with their corresponding template arguments. In this case, ```cpp template <template <Concept C> class T> void foo(T<int>); ``` T lies at the depth 0, and C lies at 1. The corresponding argument, of which there is exactly one, int, is at depth 0. If we consider the argument as the outermost one, then we would end up substituting 'int' into the wrong parameter T. We used to perform such placeholder construction during the context walk-up. In the previous patch, we slipped through that inadvertently because we would walk up to the parent, which is precisely a FileContext for template-template parameters, after adding innermost arguments. Besides, this patch moves the sanity check up to the context switch. That way, we avoid dereferencing null pointers if ND is unspecified. Closes #57410. Closes #76604. (The case is slightly different than that in #57410. We should *not* assume the surrounding context to be a file-scope one.)
1 parent 8bbf100 commit 0c7d46a

File tree

3 files changed

+51
-8
lines changed

3 files changed

+51
-8
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,11 @@ Bug Fixes to C++ Support
857857
(`#64607 <https://github.com/llvm/llvm-project/issues/64607>`_)
858858
(`#64086 <https://github.com/llvm/llvm-project/issues/64086>`_)
859859

860+
- Fixed a regression where clang forgets how to substitute into constraints on template-template
861+
parameters. Fixes:
862+
(`#57410 <https://github.com/llvm/llvm-project/issues/57410>`_) and
863+
(`#76604 <https://github.com/llvm/llvm-project/issues/57410>`_)
864+
860865
Bug Fixes to AST Handling
861866
^^^^^^^^^^^^^^^^^^^^^^^^^
862867
- Fixed an import failure of recursive friend class template.

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -344,15 +344,26 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
344344

345345
using namespace TemplateInstArgsHelpers;
346346
const Decl *CurDecl = ND;
347+
348+
if (!CurDecl)
349+
CurDecl = Decl::castFromDeclContext(DC);
350+
347351
if (Innermost) {
348352
Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND),
349353
Innermost->asArray(), Final);
350-
CurDecl = Response::UseNextDecl(ND).NextDecl;
354+
// Populate placeholder template arguments for TemplateTemplateParmDecls.
355+
// This is essential for the case e.g.
356+
//
357+
// template <class> concept Concept = false;
358+
// template <template <Concept C> class T> void foo(T<int>)
359+
//
360+
// where parameter C has a depth of 1 but the substituting argument `int`
361+
// has a depth of 0.
362+
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl))
363+
HandleDefaultTempArgIntoTempTempParam(TTP, Result);
364+
CurDecl = Response::UseNextDecl(CurDecl).NextDecl;
351365
}
352366

353-
if (!ND)
354-
CurDecl = Decl::castFromDeclContext(DC);
355-
356367
while (!CurDecl->isFileContextDecl()) {
357368
Response R;
358369
if (const auto *VarTemplSpec =
@@ -380,10 +391,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
380391
R = Response::ChangeDecl(CTD->getLexicalDeclContext());
381392
} else if (!isa<DeclContext>(CurDecl)) {
382393
R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl);
383-
if (CurDecl->getDeclContext()->isTranslationUnit()) {
384-
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
385-
R = HandleDefaultTempArgIntoTempTempParam(TTP, Result);
386-
}
394+
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
395+
R = HandleDefaultTempArgIntoTempTempParam(TTP, Result);
387396
}
388397
} else {
389398
R = HandleGenericDeclContext(CurDecl);

clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,32 @@ struct Nothing {};
5959

6060
// FIXME: Wait the standard to clarify the intent.
6161
template<> template<> Z<Nothing> S5<Z>::V<Nothing>;
62+
63+
namespace GH57410 {
64+
65+
template<typename T>
66+
concept True = true;
67+
68+
template<typename T>
69+
concept False = false; // #False
70+
71+
template <class> struct S {};
72+
73+
template<template<True T> typename Wrapper>
74+
using Test = Wrapper<int>;
75+
76+
template<template<False T> typename Wrapper> // #TTP-Wrapper
77+
using Test = Wrapper<int>; // expected-error {{constraints not satisfied for template template parameter 'Wrapper' [with T = int]}}
78+
79+
// expected-note@#TTP-Wrapper {{'int' does not satisfy 'False'}}
80+
// expected-note@#False {{evaluated to false}}
81+
82+
template <typename U, template<False> typename T>
83+
void foo(T<U>); // #foo
84+
85+
void bar() {
86+
foo<int>(S<int>{}); // expected-error {{no matching function for call to 'foo'}}
87+
// expected-note@#foo {{substitution failure [with U = int]: constraints not satisfied for template template parameter 'T' [with $0 = int]}}
88+
}
89+
90+
}

0 commit comments

Comments
 (0)