Skip to content

Commit

Permalink
[Clang][Sema] Use the correct injected template arguments for partial…
Browse files Browse the repository at this point in the history
… specializations when collecting multi-level template argument lists (llvm#112381)

After llvm#111852 refactored multi-level template argument list collection,
the following results in a crash:
```
template<typename T, bool B>
struct A;

template<bool B>
struct A<int, B>
{
    void f() requires B;
};

template<bool B>
void A<int, B>::f() requires B { } // crash here
```

This happens because when collecting template arguments for constraint
normalization from a partial specialization, we incorrectly use the
template argument list of the partial specialization. We should be using
the template argument list of the _template-head_ (as defined in
[temp.arg.general] p2). Fixes llvm#112222.
  • Loading branch information
sdkrystian authored and EricWF committed Oct 22, 2024
1 parent 6b053c6 commit 90a2214
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 123 deletions.
18 changes: 17 additions & 1 deletion clang/include/clang/AST/DeclTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -2085,7 +2085,11 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
class ClassTemplatePartialSpecializationDecl
: public ClassTemplateSpecializationDecl {
/// The list of template parameters
TemplateParameterList* TemplateParams = nullptr;
TemplateParameterList *TemplateParams = nullptr;

/// The set of "injected" template arguments used within this
/// partial specialization.
TemplateArgument *InjectedArgs = nullptr;

/// The class template partial specialization from which this
/// class template partial specialization was instantiated.
Expand Down Expand Up @@ -2132,6 +2136,10 @@ class ClassTemplatePartialSpecializationDecl
return TemplateParams;
}

/// Retrieve the template arguments list of the template parameter list
/// of this template.
ArrayRef<TemplateArgument> getInjectedTemplateArgs();

/// \brief All associated constraints of this partial specialization,
/// including the requires clause and any constraints derived from
/// constrained-parameters.
Expand Down Expand Up @@ -2856,6 +2864,10 @@ class VarTemplatePartialSpecializationDecl
/// The list of template parameters
TemplateParameterList *TemplateParams = nullptr;

/// The set of "injected" template arguments used within this
/// partial specialization.
TemplateArgument *InjectedArgs = nullptr;

/// The variable template partial specialization from which this
/// variable template partial specialization was instantiated.
///
Expand Down Expand Up @@ -2902,6 +2914,10 @@ class VarTemplatePartialSpecializationDecl
return TemplateParams;
}

/// Retrieve the template arguments list of the template parameter list
/// of this template.
ArrayRef<TemplateArgument> getInjectedTemplateArgs();

/// \brief All associated constraints of this partial specialization,
/// including the requires clause and any constraints derived from
/// constrained-parameters.
Expand Down
28 changes: 28 additions & 0 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,20 @@ SourceRange ClassTemplatePartialSpecializationDecl::getSourceRange() const {
return Range;
}

ArrayRef<TemplateArgument>
ClassTemplatePartialSpecializationDecl::getInjectedTemplateArgs() {
TemplateParameterList *Params = getTemplateParameters();
auto *First = cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
if (!First->InjectedArgs) {
auto &Context = getASTContext();
SmallVector<TemplateArgument, 16> TemplateArgs;
Context.getInjectedTemplateArgs(Params, TemplateArgs);
First->InjectedArgs = new (Context) TemplateArgument[TemplateArgs.size()];
std::copy(TemplateArgs.begin(), TemplateArgs.end(), First->InjectedArgs);
}
return llvm::ArrayRef(First->InjectedArgs, Params->size());
}

//===----------------------------------------------------------------------===//
// FriendTemplateDecl Implementation
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1535,6 +1549,20 @@ SourceRange VarTemplatePartialSpecializationDecl::getSourceRange() const {
return Range;
}

ArrayRef<TemplateArgument>
VarTemplatePartialSpecializationDecl::getInjectedTemplateArgs() {
TemplateParameterList *Params = getTemplateParameters();
auto *First = cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
if (!First->InjectedArgs) {
auto &Context = getASTContext();
SmallVector<TemplateArgument, 16> TemplateArgs;
Context.getInjectedTemplateArgs(Params, TemplateArgs);
First->InjectedArgs = new (Context) TemplateArgument[TemplateArgs.size()];
std::copy(TemplateArgs.begin(), TemplateArgs.end(), First->InjectedArgs);
}
return llvm::ArrayRef(First->InjectedArgs, Params->size());
}

static TemplateParameterList *
createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) {
// typename T
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ struct TemplateInstantiationArgumentCollecter
if (Innermost)
AddInnermostTemplateArguments(VTPSD);
else if (ForConstraintInstantiation)
AddOuterTemplateArguments(VTPSD, VTPSD->getTemplateArgs().asArray(),
AddOuterTemplateArguments(VTPSD, VTPSD->getInjectedTemplateArgs(),
/*Final=*/false);

if (VTPSD->isMemberSpecialization())
Expand Down Expand Up @@ -274,7 +274,7 @@ struct TemplateInstantiationArgumentCollecter
if (Innermost)
AddInnermostTemplateArguments(CTPSD);
else if (ForConstraintInstantiation)
AddOuterTemplateArguments(CTPSD, CTPSD->getTemplateArgs().asArray(),
AddOuterTemplateArguments(CTPSD, CTPSD->getInjectedTemplateArgs(),
/*Final=*/false);

if (CTPSD->isMemberSpecialization())
Expand Down
Loading

0 comments on commit 90a2214

Please sign in to comment.