Skip to content

Commit 29b5f8f

Browse files
authored
[Clang][Sema] Extract ellipsis location from CXXFoldExpr for reattaching constraints on NTTPs (llvm#78080)
We build up a `CXXFoldExpr` for immediately declared constraints as per C++20 [temp.param]/4. This is done by `formImmediatelyDeclaredConstraint` where an `EllipsisLoc` is essential to determine whether this is a pack. On the other hand, when attempting to instantiate a class template, member templates might not be instantiated immediately, so we leave them intact. For function templates with NTTPs, we reattach constraints if possible so that they can be evaluated later. To properly form that, we attempted to extract an ellipsis location if the param per se was a parameter pack. Unfortunately, for the following NTTP case, we seemingly failed to handle: ```cpp template <Constraint auto... Pack> void member(); ``` The NTTPD Pack is neither an `ExpandedParameterPack` nor a `PackExpansion` (its type does not expand anything). As a result, we end up losing track of the constraints on packs, although we have them inside the associated `CXXFoldExpr`. This patch fixes that by extracting the ellipsis location out of the previous constraint expression. Closes llvm#63837.
1 parent a4cd99e commit 29b5f8f

File tree

3 files changed

+37
-8
lines changed

3 files changed

+37
-8
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,9 @@ Bug Fixes to C++ Support
917917
(`#64607 <https://github.com/llvm/llvm-project/issues/64607>`_)
918918
(`#64086 <https://github.com/llvm/llvm-project/issues/64086>`_)
919919

920+
- Fixed a crash where we lost uninstantiated constraints on placeholder NTTP packs. Fixes:
921+
(`#63837 <https://github.com/llvm/llvm-project/issues/63837>`_)
922+
920923
- Fixed a regression where clang forgets how to substitute into constraints on template-template
921924
parameters. Fixes:
922925
(`#57410 <https://github.com/llvm/llvm-project/issues/57410>`_) and

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3056,16 +3056,21 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
30563056
D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI);
30573057

30583058
if (AutoTypeLoc AutoLoc = DI->getTypeLoc().getContainedAutoTypeLoc())
3059-
if (AutoLoc.isConstrained())
3059+
if (AutoLoc.isConstrained()) {
3060+
SourceLocation EllipsisLoc;
3061+
if (IsExpandedParameterPack)
3062+
EllipsisLoc =
3063+
DI->getTypeLoc().getAs<PackExpansionTypeLoc>().getEllipsisLoc();
3064+
else if (auto *Constraint = dyn_cast_if_present<CXXFoldExpr>(
3065+
D->getPlaceholderTypeConstraint()))
3066+
EllipsisLoc = Constraint->getEllipsisLoc();
30603067
// Note: We attach the uninstantiated constriant here, so that it can be
3061-
// instantiated relative to the top level, like all our other constraints.
3062-
if (SemaRef.AttachTypeConstraint(
3063-
AutoLoc, Param, D,
3064-
IsExpandedParameterPack
3065-
? DI->getTypeLoc().getAs<PackExpansionTypeLoc>()
3066-
.getEllipsisLoc()
3067-
: SourceLocation()))
3068+
// instantiated relative to the top level, like all our other
3069+
// constraints.
3070+
if (SemaRef.AttachTypeConstraint(AutoLoc, /*NewConstrainedParm=*/Param,
3071+
/*OrigConstrainedParm=*/D, EllipsisLoc))
30683072
Invalid = true;
3073+
}
30693074

30703075
Param->setAccess(AS_public);
30713076
Param->setImplicit(D->isImplicit());

clang/test/SemaTemplate/concepts.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,3 +1064,24 @@ void cand(T t)
10641064

10651065
void test() { cand(42); }
10661066
}
1067+
1068+
namespace GH63837 {
1069+
1070+
template<class> concept IsFoo = true;
1071+
1072+
template<class> struct Struct {
1073+
template<IsFoo auto... xs>
1074+
void foo() {}
1075+
1076+
template<auto... xs> requires (... && IsFoo<decltype(xs)>)
1077+
void bar() {}
1078+
1079+
template<IsFoo auto... xs>
1080+
static inline int field = 0;
1081+
};
1082+
1083+
template void Struct<void>::foo<>();
1084+
template void Struct<void>::bar<>();
1085+
template int Struct<void>::field<1, 2>;
1086+
1087+
}

0 commit comments

Comments
 (0)