aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatheus Izvekov <mizvekov@gmail.com>2025-09-24 17:18:41 -0300
committerMatheus Izvekov <mizvekov@gmail.com>2025-09-26 16:18:42 -0300
commit1160542a693e22cc81c719e371d1b6282ecc3800 (patch)
tree1c23ff6c8b9bc54926911560b84450d937e51047
parent21fe7eea5c0f7dbfe8b08251a594c23ea2e8980d (diff)
downloadllvm-users/mizvekov/fix-substnttp-transform.zip
llvm-users/mizvekov/fix-substnttp-transform.tar.gz
llvm-users/mizvekov/fix-substnttp-transform.tar.bz2
[clang] fix transformation of subst constant template parameter nodesusers/mizvekov/fix-substnttp-transform
This simplifies those transforms a lot, removing a bunch of workarounds which were introducing problems. The transforms become independent of the template instantiator, so they are moved to TreeTransform instead. Fixes #131342
-rw-r--r--clang/docs/ReleaseNotes.rst1
-rw-r--r--clang/include/clang/AST/ExprCXX.h2
-rw-r--r--clang/include/clang/AST/TypeBase.h4
-rw-r--r--clang/include/clang/Sema/Sema.h17
-rw-r--r--clang/lib/AST/ExprCXX.cpp4
-rw-r--r--clang/lib/AST/StmtProfile.cpp3
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp34
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp203
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp23
-rw-r--r--clang/lib/Sema/TreeTransform.h72
-rw-r--r--clang/test/SemaCXX/ctad.cpp7
-rw-r--r--clang/test/SemaCXX/cxx20-ctad-type-alias.cpp2
-rw-r--r--clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp11
13 files changed, 168 insertions, 215 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 703fe2a..99ca301 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -361,6 +361,7 @@ Bug Fixes in This Version
first parameter. (#GH113323).
- Fixed a crash with incompatible pointer to integer conversions in designated
initializers involving string literals. (#GH154046)
+- Fix crash on CTAD for alias template. (#GH131342)
- Clang now emits a frontend error when a function marked with the `flatten` attribute
calls another function that requires target features not enabled in the caller. This
prevents a fatal error in the backend.
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 9fedb23..5f16bac 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4714,7 +4714,7 @@ public:
// sugared: it doesn't need to be resugared later.
bool getFinal() const { return Final; }
- NamedDecl *getParameter() const;
+ NonTypeTemplateParmDecl *getParameter() const;
bool isReferenceParameter() const { return AssociatedDeclAndRef.getInt(); }
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
index b02d9c7..e0d00b8 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -3495,7 +3495,9 @@ protected:
AdjustedType(TypeClass TC, QualType OriginalTy, QualType AdjustedTy,
QualType CanonicalPtr)
- : Type(TC, CanonicalPtr, OriginalTy->getDependence()),
+ : Type(TC, CanonicalPtr,
+ AdjustedTy->getDependence() |
+ (OriginalTy->getDependence() & ~TypeDependence::Dependent)),
OriginalTy(OriginalTy), AdjustedTy(AdjustedTy) {}
public:
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5edfc29..2bd6be2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11714,6 +11714,23 @@ public:
const TemplateArgumentListInfo *TemplateArgs,
bool IsAddressOfOperand);
+ UnsignedOrNone getPackIndex(TemplateArgument Pack) const {
+ return Pack.pack_size() - 1 - *ArgPackSubstIndex;
+ }
+
+ TemplateArgument
+ getPackSubstitutedTemplateArgument(TemplateArgument Arg) const {
+ Arg = Arg.pack_elements()[*ArgPackSubstIndex];
+ if (Arg.isPackExpansion())
+ Arg = Arg.getPackExpansionPattern();
+ return Arg;
+ }
+
+ ExprResult BuildSubstNonTypeTemplateParmExpr(
+ Decl *AssociatedDecl, const NonTypeTemplateParmDecl *NTTP,
+ SourceLocation loc, TemplateArgument Replacement,
+ UnsignedOrNone PackIndex, bool Final);
+
/// Form a template name from a name that is syntactically required to name a
/// template, either due to use of the 'template' keyword or because a name in
/// this syntactic context is assumed to name a template (C++
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 97ae4a0..95de6a8 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1725,8 +1725,8 @@ SizeOfPackExpr *SizeOfPackExpr::CreateDeserialized(ASTContext &Context,
return new (Storage) SizeOfPackExpr(EmptyShell(), NumPartialArgs);
}
-NamedDecl *SubstNonTypeTemplateParmExpr::getParameter() const {
- return cast<NamedDecl>(
+NonTypeTemplateParmDecl *SubstNonTypeTemplateParmExpr::getParameter() const {
+ return cast<NonTypeTemplateParmDecl>(
getReplacedTemplateParameterList(getAssociatedDecl())->asArray()[Index]);
}
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 37c4d43..8b3af94 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1353,7 +1353,8 @@ void StmtProfiler::VisitExpr(const Expr *S) {
}
void StmtProfiler::VisitConstantExpr(const ConstantExpr *S) {
- VisitExpr(S);
+ // Profile exactly as the sub-expression.
+ Visit(S->getSubExpr());
}
void StmtProfiler::VisitDeclRefExpr(const DeclRefExpr *S) {
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 91e4dc8..3ebbb30 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -775,6 +775,40 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
TemplateArgs);
}
+ExprResult Sema::BuildSubstNonTypeTemplateParmExpr(
+ Decl *AssociatedDecl, const NonTypeTemplateParmDecl *NTTP,
+ SourceLocation Loc, TemplateArgument Arg, UnsignedOrNone PackIndex,
+ bool Final) {
+ // The template argument itself might be an expression, in which case we just
+ // return that expression. This happens when substituting into an alias
+ // template.
+ Expr *Replacement;
+ bool refParam = true;
+ if (Arg.getKind() == TemplateArgument::Expression) {
+ Replacement = Arg.getAsExpr();
+ refParam = Replacement->isLValue();
+ if (refParam && Replacement->getType()->isRecordType()) {
+ QualType ParamType =
+ NTTP->isExpandedParameterPack()
+ ? NTTP->getExpansionType(*SemaRef.ArgPackSubstIndex)
+ : NTTP->getType();
+ if (const auto *PET = dyn_cast<PackExpansionType>(ParamType))
+ ParamType = PET->getPattern();
+ refParam = ParamType->isReferenceType();
+ }
+ } else {
+ ExprResult result =
+ SemaRef.BuildExpressionFromNonTypeTemplateArgument(Arg, Loc);
+ if (result.isInvalid())
+ return ExprError();
+ Replacement = result.get();
+ refParam = Arg.getNonTypeTemplateArgumentType()->isReferenceType();
+ }
+ return new (SemaRef.Context) SubstNonTypeTemplateParmExpr(
+ Replacement->getType(), Replacement->getValueKind(), Loc, Replacement,
+ AssociatedDecl, NTTP->getIndex(), PackIndex, refParam, Final);
+}
+
bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
NamedDecl *Instantiation,
bool InstantiatedFromMember,
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index a72c95d..1ff94d7 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1373,16 +1373,6 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
return std::nullopt;
}
-static TemplateArgument
-getPackSubstitutedTemplateArgument(Sema &S, TemplateArgument Arg) {
- assert(S.ArgPackSubstIndex);
- assert(*S.ArgPackSubstIndex < Arg.pack_size());
- Arg = Arg.pack_begin()[*S.ArgPackSubstIndex];
- if (Arg.isPackExpansion())
- Arg = Arg.getPackExpansionPattern();
- return Arg;
-}
-
//===----------------------------------------------------------------------===/
// Template Instantiation for Types
//===----------------------------------------------------------------------===/
@@ -1449,13 +1439,6 @@ namespace {
return TemplateArgs.getNewDepth(Depth);
}
- UnsignedOrNone getPackIndex(TemplateArgument Pack) {
- UnsignedOrNone Index = getSema().ArgPackSubstIndex;
- if (!Index)
- return std::nullopt;
- return Pack.pack_size() - 1 - *Index;
- }
-
bool TryExpandParameterPacks(SourceLocation EllipsisLoc,
SourceRange PatternRange,
ArrayRef<UnexpandedParameterPack> Unexpanded,
@@ -1537,7 +1520,7 @@ namespace {
if (TA.getKind() != TemplateArgument::Pack)
return TA;
if (SemaRef.ArgPackSubstIndex)
- return getPackSubstitutedTemplateArgument(SemaRef, TA);
+ return SemaRef.getPackSubstitutedTemplateArgument(TA);
assert(TA.pack_size() == 1 && TA.pack_begin()->isPackExpansion() &&
"unexpected pack arguments in template rewrite");
TemplateArgument Arg = *TA.pack_begin();
@@ -1643,10 +1626,6 @@ namespace {
ExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
NonTypeTemplateParmDecl *D);
- ExprResult TransformSubstNonTypeTemplateParmPackExpr(
- SubstNonTypeTemplateParmPackExpr *E);
- ExprResult TransformSubstNonTypeTemplateParmExpr(
- SubstNonTypeTemplateParmExpr *E);
/// Rebuild a DeclRefExpr for a VarDecl reference.
ExprResult RebuildVarDeclRefExpr(ValueDecl *PD, SourceLocation Loc);
@@ -1933,12 +1912,6 @@ namespace {
SmallVectorImpl<QualType> &PTypes,
SmallVectorImpl<ParmVarDecl *> &TransParams,
Sema::ExtParameterInfoBuilder &PInfos);
-
- private:
- ExprResult
- transformNonTypeTemplateParmRef(Decl *AssociatedDecl, const NamedDecl *parm,
- SourceLocation loc, TemplateArgument arg,
- UnsignedOrNone PackIndex, bool Final);
};
}
@@ -1975,7 +1948,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
if (TTP->isParameterPack()) {
assert(Arg.getKind() == TemplateArgument::Pack &&
"Missing argument pack");
- Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
+ Arg = SemaRef.getPackSubstitutedTemplateArgument(Arg);
}
TemplateName Template = Arg.getAsTemplate();
@@ -2079,7 +2052,7 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
if (!getSema().ArgPackSubstIndex)
return nullptr;
- Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
+ Arg = SemaRef.getPackSubstitutedTemplateArgument(Arg);
}
QualType T = Arg.getAsType();
@@ -2165,8 +2138,8 @@ TemplateName TemplateInstantiator::TransformTemplateName(
Arg, AssociatedDecl, TTP->getIndex(), Final);
}
- PackIndex = getPackIndex(Arg);
- Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
+ PackIndex = SemaRef.getPackIndex(Arg);
+ Arg = SemaRef.getPackSubstitutedTemplateArgument(Arg);
}
TemplateName Template = Arg.getAsTemplate();
@@ -2183,10 +2156,10 @@ TemplateName TemplateInstantiator::TransformTemplateName(
TemplateArgument Pack = SubstPack->getArgumentPack();
TemplateName Template =
- getPackSubstitutedTemplateArgument(getSema(), Pack).getAsTemplate();
+ SemaRef.getPackSubstitutedTemplateArgument(Pack).getAsTemplate();
return getSema().Context.getSubstTemplateTemplateParm(
Template, SubstPack->getAssociatedDecl(), SubstPack->getIndex(),
- getPackIndex(Pack), SubstPack->getFinal());
+ SemaRef.getPackIndex(Pack), SubstPack->getFinal());
}
return inherited::TransformTemplateName(
@@ -2252,11 +2225,11 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
ExprType, TargetType->isReferenceType() ? VK_LValue : VK_PRValue,
E->getLocation(), Arg, AssociatedDecl, NTTP->getPosition(), Final);
}
- PackIndex = getPackIndex(Arg);
- Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
+ PackIndex = SemaRef.getPackIndex(Arg);
+ Arg = SemaRef.getPackSubstitutedTemplateArgument(Arg);
}
- return transformNonTypeTemplateParmRef(AssociatedDecl, NTTP, E->getLocation(),
- Arg, PackIndex, Final);
+ return SemaRef.BuildSubstNonTypeTemplateParmExpr(
+ AssociatedDecl, NTTP, E->getLocation(), Arg, PackIndex, Final);
}
const AnnotateAttr *
@@ -2344,144 +2317,6 @@ TemplateInstantiator::TransformOpenACCRoutineDeclAttr(
"applies to a Function Decl (and a few places for VarDecl)");
}
-ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef(
- Decl *AssociatedDecl, const NamedDecl *parm, SourceLocation loc,
- TemplateArgument arg, UnsignedOrNone PackIndex, bool Final) {
- ExprResult result;
-
- // Determine the substituted parameter type. We can usually infer this from
- // the template argument, but not always.
- auto SubstParamType = [&] {
- if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(parm)) {
- QualType T;
- if (NTTP->isExpandedParameterPack())
- T = NTTP->getExpansionType(*SemaRef.ArgPackSubstIndex);
- else
- T = NTTP->getType();
- if (parm->isParameterPack() && isa<PackExpansionType>(T))
- T = cast<PackExpansionType>(T)->getPattern();
- return SemaRef.SubstType(T, TemplateArgs, loc, parm->getDeclName());
- }
- return SemaRef.SubstType(arg.getAsExpr()->getType(), TemplateArgs, loc,
- parm->getDeclName());
- };
-
- bool refParam = false;
-
- // The template argument itself might be an expression, in which case we just
- // return that expression. This happens when substituting into an alias
- // template.
- if (arg.getKind() == TemplateArgument::Expression) {
- Expr *argExpr = arg.getAsExpr();
- result = argExpr;
- if (argExpr->isLValue()) {
- if (argExpr->getType()->isRecordType()) {
- // Check whether the parameter was actually a reference.
- QualType paramType = SubstParamType();
- if (paramType.isNull())
- return ExprError();
- refParam = paramType->isReferenceType();
- } else {
- refParam = true;
- }
- }
- } else if (arg.getKind() == TemplateArgument::Declaration ||
- arg.getKind() == TemplateArgument::NullPtr) {
- if (arg.getKind() == TemplateArgument::Declaration) {
- ValueDecl *VD = arg.getAsDecl();
-
- // Find the instantiation of the template argument. This is
- // required for nested templates.
- VD = cast_or_null<ValueDecl>(
- getSema().FindInstantiatedDecl(loc, VD, TemplateArgs));
- if (!VD)
- return ExprError();
- }
-
- QualType paramType = arg.getNonTypeTemplateArgumentType();
- assert(!paramType.isNull() && "type substitution failed for param type");
- assert(!paramType->isDependentType() && "param type still dependent");
- result = SemaRef.BuildExpressionFromDeclTemplateArgument(arg, paramType, loc);
- refParam = paramType->isReferenceType();
- } else {
- QualType paramType = arg.getNonTypeTemplateArgumentType();
- result = SemaRef.BuildExpressionFromNonTypeTemplateArgument(arg, loc);
- refParam = paramType->isReferenceType();
- assert(result.isInvalid() ||
- SemaRef.Context.hasSameType(result.get()->getType(),
- paramType.getNonReferenceType()));
- }
-
- if (result.isInvalid())
- return ExprError();
-
- Expr *resultExpr = result.get();
- return new (SemaRef.Context) SubstNonTypeTemplateParmExpr(
- resultExpr->getType(), resultExpr->getValueKind(), loc, resultExpr,
- AssociatedDecl,
- clang::getDepthAndIndex(const_cast<NamedDecl *>(parm)).second, PackIndex,
- refParam, Final);
-}
-
-ExprResult
-TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
- SubstNonTypeTemplateParmPackExpr *E) {
- if (!getSema().ArgPackSubstIndex) {
- // We aren't expanding the parameter pack, so just return ourselves.
- return E;
- }
-
- TemplateArgument Pack = E->getArgumentPack();
- TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack);
- return transformNonTypeTemplateParmRef(
- E->getAssociatedDecl(), E->getParameterPack(),
- E->getParameterPackLocation(), Arg, getPackIndex(Pack), E->getFinal());
-}
-
-ExprResult
-TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr(
- SubstNonTypeTemplateParmExpr *E) {
- ExprResult SubstReplacement = E->getReplacement();
- if (!isa<ConstantExpr>(SubstReplacement.get()))
- SubstReplacement = TransformExpr(E->getReplacement());
- if (SubstReplacement.isInvalid())
- return true;
- QualType SubstType = TransformType(E->getParameterType(getSema().Context));
- if (SubstType.isNull())
- return true;
- // The type may have been previously dependent and not now, which means we
- // might have to implicit cast the argument to the new type, for example:
- // template<auto T, decltype(T) U>
- // concept C = sizeof(U) == 4;
- // void foo() requires C<2, 'a'> { }
- // When normalizing foo(), we first form the normalized constraints of C:
- // AtomicExpr(sizeof(U) == 4,
- // U=SubstNonTypeTemplateParmExpr(Param=U,
- // Expr=DeclRef(U),
- // Type=decltype(T)))
- // Then we substitute T = 2, U = 'a' into the parameter mapping, and need to
- // produce:
- // AtomicExpr(sizeof(U) == 4,
- // U=SubstNonTypeTemplateParmExpr(Param=U,
- // Expr=ImpCast(
- // decltype(2),
- // SubstNTTPE(Param=U, Expr='a',
- // Type=char)),
- // Type=decltype(2)))
- // The call to CheckTemplateArgument here produces the ImpCast.
- TemplateArgument SugaredConverted, CanonicalConverted;
- if (SemaRef
- .CheckTemplateArgument(E->getParameter(), SubstType,
- SubstReplacement.get(), SugaredConverted,
- CanonicalConverted,
- /*StrictCheck=*/false, Sema::CTAK_Specified)
- .isInvalid())
- return true;
- return transformNonTypeTemplateParmRef(
- E->getAssociatedDecl(), E->getParameter(), E->getExprLoc(),
- SugaredConverted, E->getPackIndex(), E->getFinal());
-}
-
ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(ValueDecl *PD,
SourceLocation Loc) {
DeclarationNameInfo NameInfo(PD->getDeclName(), Loc);
@@ -2701,8 +2536,8 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
}
// PackIndex starts from last element.
- PackIndex = getPackIndex(Arg);
- Arg = getPackSubstitutedTemplateArgument(getSema(), Arg);
+ PackIndex = SemaRef.getPackIndex(Arg);
+ Arg = SemaRef.getPackSubstitutedTemplateArgument(Arg);
}
assert(Arg.getKind() == TemplateArgument::Type &&
@@ -2749,20 +2584,20 @@ QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType(
}
TemplateArgument Pack = T->getArgumentPack();
- TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack);
+ TemplateArgument Arg = SemaRef.getPackSubstitutedTemplateArgument(Pack);
return BuildSubstTemplateTypeParmType(
TLB, SuppressObjCLifetime, T->getFinal(), NewReplaced, T->getIndex(),
- getPackIndex(Pack), Arg, TL.getNameLoc());
+ SemaRef.getPackIndex(Pack), Arg, TL.getNameLoc());
}
QualType TemplateInstantiator::TransformSubstBuiltinTemplatePackType(
TypeLocBuilder &TLB, SubstBuiltinTemplatePackTypeLoc TL) {
if (!getSema().ArgPackSubstIndex)
return TreeTransform::TransformSubstBuiltinTemplatePackType(TLB, TL);
- auto &Sema = getSema();
- TemplateArgument Result = getPackSubstitutedTemplateArgument(
- Sema, TL.getTypePtr()->getArgumentPack());
- TLB.pushTrivial(Sema.getASTContext(), Result.getAsType(), TL.getBeginLoc());
+ TemplateArgument Result = SemaRef.getPackSubstitutedTemplateArgument(
+ TL.getTypePtr()->getArgumentPack());
+ TLB.pushTrivial(SemaRef.getASTContext(), Result.getAsType(),
+ TL.getBeginLoc());
return Result.getAsType();
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index adac3df..e2dc703 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3742,7 +3742,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
ExpandedParams.reserve(D->getNumExpansionTemplateParameters());
for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
I != N; ++I) {
- LocalInstantiationScope Scope(SemaRef);
+ LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
TemplateParameterList *Expansion =
SubstTemplateParams(D->getExpansionTemplateParameters(I));
if (!Expansion)
@@ -3774,7 +3774,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
if (Expand) {
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgPackSubstIndexRAII SubstIndex(SemaRef, I);
- LocalInstantiationScope Scope(SemaRef);
+ LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
TemplateParameterList *Expansion = SubstTemplateParams(TempParams);
if (!Expansion)
return nullptr;
@@ -3785,21 +3785,18 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
// expanded parameter pack is the original expansion type, but callers
// will end up using the expanded parameter pack types for type-checking.
IsExpandedParameterPack = true;
- InstParams = TempParams;
- } else {
- // We cannot fully expand the pack expansion now, so just substitute
- // into the pattern.
- Sema::ArgPackSubstIndexRAII SubstIndex(SemaRef, std::nullopt);
-
- LocalInstantiationScope Scope(SemaRef);
- InstParams = SubstTemplateParams(TempParams);
- if (!InstParams)
- return nullptr;
}
+
+ Sema::ArgPackSubstIndexRAII SubstIndex(SemaRef, std::nullopt);
+
+ LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+ InstParams = SubstTemplateParams(TempParams);
+ if (!InstParams)
+ return nullptr;
} else {
// Perform the actual substitution of template parameters within a new,
// local instantiation scope.
- LocalInstantiationScope Scope(SemaRef);
+ LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return nullptr;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 242ffb0..0214078 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -16289,20 +16289,68 @@ TreeTransform<Derived>::TransformPackIndexingExpr(PackIndexingExpr *E) {
IndexExpr.get(), ExpandedExprs, FullySubstituted);
}
-template<typename Derived>
-ExprResult
-TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr(
- SubstNonTypeTemplateParmPackExpr *E) {
- // Default behavior is to do nothing with this transformation.
- return E;
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr(
+ SubstNonTypeTemplateParmPackExpr *E) {
+ if (!getSema().ArgPackSubstIndex)
+ // We aren't expanding the parameter pack, so just return ourselves.
+ return E;
+
+ TemplateArgument Pack = E->getArgumentPack();
+ TemplateArgument Arg = SemaRef.getPackSubstitutedTemplateArgument(Pack);
+ return SemaRef.BuildSubstNonTypeTemplateParmExpr(
+ E->getAssociatedDecl(), E->getParameterPack(),
+ E->getParameterPackLocation(), Arg, SemaRef.getPackIndex(Pack),
+ E->getFinal());
}
-template<typename Derived>
-ExprResult
-TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr(
- SubstNonTypeTemplateParmExpr *E) {
- // Default behavior is to do nothing with this transformation.
- return E;
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *E) {
+ Expr *OrigReplacement = E->getReplacement()->IgnoreImplicitAsWritten();
+ ExprResult Replacement = getDerived().TransformExpr(OrigReplacement);
+ if (Replacement.isInvalid())
+ return true;
+
+ Decl *AssociatedDecl =
+ getDerived().TransformDecl(E->getNameLoc(), E->getAssociatedDecl());
+ if (!AssociatedDecl)
+ return true;
+
+ if (Replacement.get() == OrigReplacement &&
+ AssociatedDecl == E->getAssociatedDecl())
+ return E;
+
+ // If the replacement expression did not change, and the parameter type
+ // did not change, we can skip the semantic action because it would
+ // produce the same result anyway.
+ auto *Param = cast<NonTypeTemplateParmDecl>(
+ getReplacedTemplateParameterList(AssociatedDecl)
+ ->asArray()[E->getIndex()]);
+ if (QualType ParamType = Param->getType();
+ !SemaRef.Context.hasSameType(ParamType, E->getParameter()->getType()) ||
+ Replacement.get() != OrigReplacement) {
+
+ // When transforming the replacement expression previously, all Sema
+ // specific annotations, such as implicit casts, are discarded. Calling the
+ // corresponding sema action is necessary to recover those. Otherwise,
+ // equivalency of the result would be lost.
+ TemplateArgument SugaredConverted, CanonicalConverted;
+ Replacement = SemaRef.CheckTemplateArgument(
+ Param, ParamType, Replacement.get(), SugaredConverted,
+ CanonicalConverted,
+ /*StrictCheck=*/false, Sema::CTAK_Specified);
+ if (Replacement.isInvalid())
+ return true;
+ } else {
+ // Otherwise, the same expression would have been produced.
+ Replacement = E->getReplacement();
+ }
+
+ return new (SemaRef.Context) SubstNonTypeTemplateParmExpr(
+ Replacement.get()->getType(), Replacement.get()->getValueKind(),
+ E->getNameLoc(), Replacement.get(), AssociatedDecl, E->getIndex(),
+ E->getPackIndex(), E->isReferenceParameter(), E->getFinal());
}
template<typename Derived>
diff --git a/clang/test/SemaCXX/ctad.cpp b/clang/test/SemaCXX/ctad.cpp
index 8380b56..7de7f503 100644
--- a/clang/test/SemaCXX/ctad.cpp
+++ b/clang/test/SemaCXX/ctad.cpp
@@ -190,3 +190,10 @@ namespace GH136624 {
foo::Alias t = 0;
// expected-error@-1 {{no viable conversion from 'int' to 'GH136624::A<int>' (aka 'A<int>')}}
} // namespace GH136624
+
+namespace GH131342 {
+ template <class> constexpr int val{0};
+ template <class T, int> struct A { A(T) {} };
+ template <class T> using AA = A<T, val<T>>;
+ AA a{0};
+} // namespace GH131342
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 1f4d442..2f1817d 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -113,7 +113,7 @@ using Bar = Foo<X, sizeof(X)>; // expected-note {{candidate template ignored: co
// expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, test9::Foo<X, sizeof(X)>) Bar(test9::Foo<X, sizeof(X)>) -> test9::Foo<X, sizeof(X)>'}} \
// expected-note {{implicit deduction guide declared as 'template <typename X> requires __is_deducible(test9::Bar, test9::Foo<X, sizeof(X)>) Bar(const X (&)[sizeof(X)]) -> test9::Foo<X, sizeof(X)>'}} \
// expected-note {{candidate template ignored: constraints not satisfied [with X = int]}} \
- // expected-note {{cannot deduce template arguments for 'test9::Bar' from 'test9::Foo<int, 4UL>'}}
+ // expected-note {{cannot deduce template arguments for 'test9::Bar' from 'test9::Foo<int, sizeof(int)>'}}
Bar s = {{1}}; // expected-error {{no viable constructor or deduction guide }}
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp
index e74c031..c4ac36e 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp
@@ -123,3 +123,14 @@ Set<float> sf;
// expected-note@#C {{evaluated to false}}
} // namespace GH84052
+
+namespace error_on_type_instantiation {
+ int f(int) = delete;
+ // expected-note@-1 {{candidate function has been explicitly deleted}}
+ template<class T, decltype(f(T()))> struct X {};
+ // expected-error@-1 {{call to deleted function 'f'}}
+ template<class T> void g() { X<T, 0> x; }
+ // expected-note@-1 {{while substituting prior template arguments into non-type template parameter [with T = int]}}
+ template void g<int>();
+ // expected-note@-1 {{in instantiation of function template specialization}}
+}