Skip to content

Commit

Permalink
[Clang] Correctly construct template arguments for template template …
Browse files Browse the repository at this point in the history
…parameters (llvm#76811)

This fixes the bug introduced by

llvm@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 llvm#57410.
Closes llvm#76604. (The case is
slightly different than that in llvm#57410. We should *not* assume the
surrounding context to be a file-scope one.)
  • Loading branch information
zyn0217 authored Jan 6, 2024
1 parent 8bbf100 commit 0c7d46a
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 8 deletions.
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,11 @@ Bug Fixes to C++ Support
(`#64607 <https://github.com/llvm/llvm-project/issues/64607>`_)
(`#64086 <https://github.com/llvm/llvm-project/issues/64086>`_)

- Fixed a regression where clang forgets how to substitute into constraints on template-template
parameters. Fixes:
(`#57410 <https://github.com/llvm/llvm-project/issues/57410>`_) and
(`#76604 <https://github.com/llvm/llvm-project/issues/57410>`_)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed an import failure of recursive friend class template.
Expand Down
25 changes: 17 additions & 8 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,15 +344,26 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(

using namespace TemplateInstArgsHelpers;
const Decl *CurDecl = ND;

if (!CurDecl)
CurDecl = Decl::castFromDeclContext(DC);

if (Innermost) {
Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND),
Innermost->asArray(), Final);
CurDecl = Response::UseNextDecl(ND).NextDecl;
// Populate placeholder template arguments for TemplateTemplateParmDecls.
// This is essential for the case e.g.
//
// template <class> concept Concept = false;
// template <template <Concept C> class T> void foo(T<int>)
//
// where parameter C has a depth of 1 but the substituting argument `int`
// has a depth of 0.
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl))
HandleDefaultTempArgIntoTempTempParam(TTP, Result);
CurDecl = Response::UseNextDecl(CurDecl).NextDecl;
}

if (!ND)
CurDecl = Decl::castFromDeclContext(DC);

while (!CurDecl->isFileContextDecl()) {
Response R;
if (const auto *VarTemplSpec =
Expand Down Expand Up @@ -380,10 +391,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
R = Response::ChangeDecl(CTD->getLexicalDeclContext());
} else if (!isa<DeclContext>(CurDecl)) {
R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl);
if (CurDecl->getDeclContext()->isTranslationUnit()) {
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
R = HandleDefaultTempArgIntoTempTempParam(TTP, Result);
}
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) {
R = HandleDefaultTempArgIntoTempTempParam(TTP, Result);
}
} else {
R = HandleGenericDeclContext(CurDecl);
Expand Down
29 changes: 29 additions & 0 deletions clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,32 @@ struct Nothing {};

// FIXME: Wait the standard to clarify the intent.
template<> template<> Z<Nothing> S5<Z>::V<Nothing>;

namespace GH57410 {

template<typename T>
concept True = true;

template<typename T>
concept False = false; // #False

template <class> struct S {};

template<template<True T> typename Wrapper>
using Test = Wrapper<int>;

template<template<False T> typename Wrapper> // #TTP-Wrapper
using Test = Wrapper<int>; // expected-error {{constraints not satisfied for template template parameter 'Wrapper' [with T = int]}}

// expected-note@#TTP-Wrapper {{'int' does not satisfy 'False'}}
// expected-note@#False {{evaluated to false}}

template <typename U, template<False> typename T>
void foo(T<U>); // #foo

void bar() {
foo<int>(S<int>{}); // expected-error {{no matching function for call to 'foo'}}
// expected-note@#foo {{substitution failure [with U = int]: constraints not satisfied for template template parameter 'T' [with $0 = int]}}
}

}

0 comments on commit 0c7d46a

Please sign in to comment.