summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatheus Izvekov <mizvekov@gmail.com>2025-09-15 01:58:01 -0300
committerMatheus Izvekov <mizvekov@gmail.com>2025-09-21 20:11:36 -0300
commita0db4a10c306786d3ab689c4094a2676c18f2c53 (patch)
treee0ca3cf71c6175f738c27c9605653715efd72458
parentcafc064fc7a96b3979a023ddae1da2b499d6c954 (diff)
[clang] WIP: implement ConstantTemplateParamCastExprusers/mizvekov/constant-template-parameter-cast
This fixes a bunch of bugs with how non-type template parameters are transformed and used in template argument deduction.
-rw-r--r--clang/include/clang/AST/ComputeDependence.h2
-rw-r--r--clang/include/clang/AST/Expr.h8
-rw-r--r--clang/include/clang/AST/ExprCXX.h56
-rw-r--r--clang/include/clang/AST/JSONNodeDumper.h2
-rw-r--r--clang/include/clang/AST/RecursiveASTVisitor.h6
-rw-r--r--clang/include/clang/AST/Stmt.h5
-rw-r--r--clang/include/clang/AST/TextNodeDumper.h2
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--clang/include/clang/Basic/StmtNodes.td1
-rw-r--r--clang/include/clang/Sema/Sema.h6
-rw-r--r--clang/include/clang/Serialization/ASTBitCodes.h3
-rw-r--r--clang/lib/AST/ComputeDependence.cpp11
-rw-r--r--clang/lib/AST/Expr.cpp1
-rw-r--r--clang/lib/AST/ExprCXX.cpp24
-rw-r--r--clang/lib/AST/ExprClassification.cpp1
-rw-r--r--clang/lib/AST/ExprConstant.cpp1
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp3
-rw-r--r--clang/lib/AST/JSONNodeDumper.cpp6
-rw-r--r--clang/lib/AST/StmtPrinter.cpp6
-rw-r--r--clang/lib/AST/StmtProfile.cpp10
-rw-r--r--clang/lib/AST/TextNodeDumper.cpp8
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp1
-rw-r--r--clang/lib/Sema/SemaOverload.cpp5
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp89
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp46
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp53
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp23
-rw-r--r--clang/lib/Sema/TreeTransform.h64
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp11
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp1
-rw-r--r--clang/test/SemaCXX/cxx20-ctad-type-alias.cpp2
-rw-r--r--clang/test/SemaCXX/delete-and-function-templates.cpp2
-rw-r--r--clang/test/SemaTemplate/make_integer_seq.cpp6
-rw-r--r--clang/test/SemaTemplate/temp_arg_nontype.cpp2
-rw-r--r--clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp11
-rw-r--r--clang/test/SemaTemplate/temp_arg_template_p0522.cpp10
-rw-r--r--clang/tools/libclang/CXCursor.cpp1
38 files changed, 345 insertions, 154 deletions
diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h
index c298f2620f21..7abe33f4d6db 100644
--- a/clang/include/clang/AST/ComputeDependence.h
+++ b/clang/include/clang/AST/ComputeDependence.h
@@ -32,6 +32,7 @@ class MatrixSubscriptExpr;
class CompoundLiteralExpr;
class ImplicitCastExpr;
class ExplicitCastExpr;
+class ConstantTemplateParamCastExpr;
class BinaryOperator;
class ConditionalOperator;
class BinaryConditionalOperator;
@@ -121,6 +122,7 @@ ExprDependence computeDependence(MatrixSubscriptExpr *E);
ExprDependence computeDependence(CompoundLiteralExpr *E);
ExprDependence computeDependence(ImplicitCastExpr *E);
ExprDependence computeDependence(ExplicitCastExpr *E);
+ExprDependence computeDependence(ConstantTemplateParamCastExpr *E);
ExprDependence computeDependence(BinaryOperator *E);
ExprDependence computeDependence(ConditionalOperator *E);
ExprDependence computeDependence(BinaryConditionalOperator *E);
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index e1a4005d1a89..2667a942479c 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -3624,7 +3624,7 @@ protected:
Expr *op, unsigned BasePathSize, bool HasFPFeatures)
: Expr(SC, ty, VK, OK_Ordinary), Op(op) {
CastExprBits.Kind = kind;
- CastExprBits.PartOfExplicitCast = false;
+ CastExprBits.ExtraData = false;
CastExprBits.BasePathSize = BasePathSize;
assert((CastExprBits.BasePathSize == BasePathSize) &&
"BasePathSize overflow!");
@@ -3636,7 +3636,7 @@ protected:
CastExpr(StmtClass SC, EmptyShell Empty, unsigned BasePathSize,
bool HasFPFeatures)
: Expr(SC, Empty) {
- CastExprBits.PartOfExplicitCast = false;
+ CastExprBits.ExtraData = false;
CastExprBits.BasePathSize = BasePathSize;
CastExprBits.HasFPFeatures = HasFPFeatures;
assert((CastExprBits.BasePathSize == BasePathSize) &&
@@ -3815,9 +3815,9 @@ public:
*getTrailingFPFeatures() = FPO;
}
- bool isPartOfExplicitCast() const { return CastExprBits.PartOfExplicitCast; }
+ bool isPartOfExplicitCast() const { return CastExprBits.ExtraData; }
void setIsPartOfExplicitCast(bool PartOfExplicitCast) {
- CastExprBits.PartOfExplicitCast = PartOfExplicitCast;
+ CastExprBits.ExtraData = PartOfExplicitCast;
}
static ImplicitCastExpr *Create(const ASTContext &Context, QualType T,
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 9fedb230ce39..325744a64940 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4653,6 +4653,62 @@ public:
}
};
+/// ImplicitCastExpr - Allows us to explicitly represent implicit type
+/// conversions, which have no direct representation in the original
+/// source code. For example: converting T[]->T*, void f()->void
+/// (*f)(), float->double, short->int, etc.
+class ConstantTemplateParamCastExpr final : public CastExpr {
+
+ NonTypeTemplateParmDecl *Param;
+
+ ConstantTemplateParamCastExpr(NonTypeTemplateParmDecl *Param, QualType ty,
+ Expr *op, ExprValueKind VK, bool IsDeduced)
+ : CastExpr(ConstantTemplateParamCastExprClass, ty, VK,
+ CastKind::CK_Dependent, op,
+ /*BasePathSize=*/0,
+ /*HasFPFeatures=*/false),
+ Param(Param) {
+ CastExprBits.ExtraData = IsDeduced;
+ setDependence(computeDependence(this));
+ }
+
+ explicit ConstantTemplateParamCastExpr(EmptyShell Shell)
+ : CastExpr(ConstantTemplateParamCastExprClass, Shell, /*BasePathSize=*/0,
+ /*HasFPFeatures=*/false) {}
+
+ template <class T> T *getTrailingObjectsNonStrict() { return nullptr; }
+
+public:
+ static ConstantTemplateParamCastExpr *Create(const ASTContext &Context,
+ NonTypeTemplateParmDecl *Param,
+ QualType ParamType,
+ Expr *Operand, bool IsDeduced);
+
+ static ConstantTemplateParamCastExpr *CreateEmpty(const ASTContext &Context) {
+ return new (Context) ConstantTemplateParamCastExpr(EmptyShell());
+ }
+
+ NonTypeTemplateParmDecl *getParam() const { return Param; }
+
+ QualType getParamType(const ASTContext &Context) const;
+
+ bool isDeduced() const { return CastExprBits.ExtraData; }
+
+ SourceLocation getBeginLoc() const LLVM_READONLY {
+ return getSubExpr()->getBeginLoc();
+ }
+ SourceLocation getEndLoc() const LLVM_READONLY {
+ return getSubExpr()->getEndLoc();
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ConstantTemplateParamCastExprClass;
+ }
+
+ friend class CastExpr;
+ friend class ASTStmtReader;
+};
+
/// Represents a reference to a non-type template parameter
/// that has been substituted with a template argument.
class SubstNonTypeTemplateParmExpr : public Expr {
diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h
index 427a9c51ece1..7da9eb3f35d3 100644
--- a/clang/include/clang/AST/JSONNodeDumper.h
+++ b/clang/include/clang/AST/JSONNodeDumper.h
@@ -297,6 +297,8 @@ public:
void VisitCXXThisExpr(const CXXThisExpr *TE);
void VisitCastExpr(const CastExpr *CE);
void VisitImplicitCastExpr(const ImplicitCastExpr *ICE);
+ void
+ VisitConstantTemplateParamCastExpr(const ConstantTemplateParamCastExpr *CE);
void VisitCallExpr(const CallExpr *CE);
void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *TTE);
void VisitSizeOfPackExpr(const SizeOfPackExpr *SOPE);
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 1d1b7f183f75..e88f90ff8ed5 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2628,6 +2628,12 @@ DEF_TRAVERSE_STMT(MemberExpr, {
S->getNumTemplateArgs()));
})
+DEF_TRAVERSE_STMT(ConstantTemplateParamCastExpr,
+ {
+ // We don't traverse the cast type, as it's not written in
+ // the source code.
+ })
+
DEF_TRAVERSE_STMT(
ImplicitCastExpr,
{// We don't traverse the cast type, as it's not written in the
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 76942f1a84f9..0dd73f28327b 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -616,14 +616,17 @@ protected:
class CastExprBitfields {
friend class CastExpr;
friend class ImplicitCastExpr;
+ friend class ConstantTemplateParamCastExpr;
LLVM_PREFERRED_TYPE(ExprBitfields)
unsigned : NumExprBits;
LLVM_PREFERRED_TYPE(CastKind)
unsigned Kind : 7;
+
+ // Used by ImplicitCastExpr and ConstantTemplateParamCastExpr.
LLVM_PREFERRED_TYPE(bool)
- unsigned PartOfExplicitCast : 1; // Only set for ImplicitCastExpr.
+ unsigned ExtraData : 1;
/// True if the call expression has some floating-point features.
LLVM_PREFERRED_TYPE(bool)
diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h
index 88ecd526e3d7..2df912479568 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -271,6 +271,8 @@ public:
void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Node);
void VisitCastExpr(const CastExpr *Node);
void VisitImplicitCastExpr(const ImplicitCastExpr *Node);
+ void
+ VisitConstantTemplateParamCastExpr(const ConstantTemplateParamCastExpr *Node);
void VisitDeclRefExpr(const DeclRefExpr *Node);
void VisitDependentScopeDeclRefExpr(const DependentScopeDeclRefExpr *Node);
void VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *Node);
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index bd896524321d..823771657c53 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5774,6 +5774,9 @@ def note_template_class_explicit_specialization_was_here : Note<
"class template %0 was explicitly specialized here">;
def note_template_class_instantiation_here : Note<
"in instantiation of template class %q0 requested here">;
+def note_non_type_template_parameter_instantiation_here
+ : Note<
+ "in instantiation of non-type template parameter %q0 requested here">;
def note_template_member_class_here : Note<
"in instantiation of member class %q0 requested here">;
def note_template_member_function_here : Note<
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index dd1a24405fae..f1f063068c72 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -86,6 +86,7 @@ def AbstractConditionalOperator : StmtNode<Expr, 1>;
def ConditionalOperator : StmtNode<AbstractConditionalOperator>;
def BinaryConditionalOperator : StmtNode<AbstractConditionalOperator>;
def ImplicitCastExpr : StmtNode<CastExpr>;
+def ConstantTemplateParamCastExpr : StmtNode<CastExpr>;
def ExplicitCastExpr : StmtNode<CastExpr, 1>;
def CStyleCastExpr : StmtNode<ExplicitCastExpr>;
def OMPArrayShapingExpr : StmtNode<Expr>;
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d017d1f82901..d409a0a09bed 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -12683,11 +12683,11 @@ public:
QualType Replacement);
// Substitute auto in TypeWithAuto for a Dependent auto type
- QualType SubstAutoTypeDependent(QualType TypeWithAuto);
+ QualType SubstAutoTypeDependent(QualType TypeWithAuto, bool IsPack = false);
// Substitute auto in TypeWithAuto for a Dependent auto type
- TypeSourceInfo *
- SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto);
+ TypeSourceInfo *SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto,
+ bool IsPack = false);
/// Completely replace the \c auto in \p TypeWithAuto by
/// \p Replacement. This does not retain any \c auto type sugar.
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index 441047d64f48..8fd9de20c9b7 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1684,6 +1684,9 @@ enum StmtCode {
/// An ImplicitCastExpr record.
EXPR_IMPLICIT_CAST,
+ /// An ConstantTemplateParamCastExpr record.
+ EXPR_CONSTANT_TEMPLATE_PARAM_CAST,
+
/// A CStyleCastExpr record.
EXPR_CSTYLE_CAST,
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index e0cf0deb12bd..51ef1b4ffb30 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -157,6 +157,17 @@ ExprDependence clang::computeDependence(ExplicitCastExpr *E) {
return D;
}
+ExprDependence clang::computeDependence(ConstantTemplateParamCastExpr *E) {
+ // We model implicit conversions as combining the dependence of their
+ // subexpression, apart from its type, with the semantic portion of the
+ // target type.
+ ExprDependence D =
+ toExprDependenceForImpliedType(E->getType()->getDependence());
+ if (auto *S = E->getSubExpr())
+ D |= S->getDependence() & ~ExprDependence::Type;
+ return D;
+}
+
ExprDependence clang::computeDependence(BinaryOperator *E) {
return E->getLHS()->getDependence() | E->getRHS()->getDependence();
}
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index f899b3c4bb79..727c89ad8b73 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3858,6 +3858,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
return true;
}
[[fallthrough]];
+ case ConstantTemplateParamCastExprClass:
case ImplicitCastExprClass:
case CStyleCastExprClass:
case CXXStaticCastExprClass:
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 97ae4a07f32a..c5f3ae8c17b8 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1765,6 +1765,30 @@ PackIndexingExpr::CreateDeserialized(ASTContext &Context,
return new (Storage) PackIndexingExpr(EmptyShell{});
}
+ConstantTemplateParamCastExpr *ConstantTemplateParamCastExpr::Create(
+ const ASTContext &C, NonTypeTemplateParmDecl *Param, QualType ParamType,
+ Expr *Operand, bool IsDeduced) {
+ return new (C) ConstantTemplateParamCastExpr(
+ Param, ParamType.getNonLValueExprType(C), Operand,
+ ParamType->isLValueReferenceType() ? VK_LValue
+ : ParamType->isRValueReferenceType() ? VK_XValue
+ : VK_PRValue,
+ IsDeduced);
+}
+
+QualType
+ConstantTemplateParamCastExpr::getParamType(const ASTContext &C) const {
+ switch (getValueKind()) {
+ case VK_LValue:
+ return C.getLValueReferenceType(getType());
+ case VK_XValue:
+ return C.getRValueReferenceType(getType());
+ case VK_PRValue:
+ return getType();
+ }
+ llvm_unreachable("unhandled value kind");
+}
+
QualType SubstNonTypeTemplateParmExpr::getParameterType(
const ASTContext &Context) const {
// Note that, for a class type NTTP, we will have an lvalue of type 'const
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index aeacd0dc765e..489584bb3ebf 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -322,6 +322,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// Implicit casts are lvalues if they're lvalue casts. Other than that, we
// only specifically record class temporaries.
+ case Expr::ConstantTemplateParamCastExprClass:
case Expr::ImplicitCastExprClass:
return ClassifyExprValueKind(Lang, E, E->getValueKind());
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 3b9ca8291003..da3bdddfa59a 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -18341,6 +18341,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
}
llvm_unreachable("invalid binary operator kind");
}
+ case Expr::ConstantTemplateParamCastExprClass:
case Expr::ImplicitCastExprClass:
case Expr::CStyleCastExprClass:
case Expr::CXXFunctionalCastExprClass:
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 2173aed5b45a..1e237dbb29e6 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -5527,9 +5527,10 @@ recurse:
break;
}
+ case Expr::ConstantTemplateParamCastExprClass:
case Expr::ImplicitCastExprClass: {
ImplicitlyConvertedToType = E->getType();
- E = cast<ImplicitCastExpr>(E)->getSubExpr();
+ E = cast<CastExpr>(E)->getSubExpr();
goto recurse;
}
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index 0ef632805d67..3a50d1fc493d 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -1459,6 +1459,12 @@ void JSONNodeDumper::VisitImplicitCastExpr(const ImplicitCastExpr *ICE) {
attributeOnlyIfTrue("isPartOfExplicitCast", ICE->isPartOfExplicitCast());
}
+void JSONNodeDumper::VisitConstantTemplateParamCastExpr(
+ const ConstantTemplateParamCastExpr *CE) {
+ VisitCastExpr(CE);
+ JOS.attribute("param", createBareDeclRef(CE->getParam()));
+}
+
void JSONNodeDumper::VisitCallExpr(const CallExpr *CE) {
attributeOnlyIfTrue("adl", CE->usesADL());
}
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 2c9c3581a296..5eb520213868 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1822,6 +1822,12 @@ void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) {
PrintExpr(Node->getInitializer());
}
+void StmtPrinter::VisitConstantTemplateParamCastExpr(
+ ConstantTemplateParamCastExpr *Node) {
+ // No need to print anything, simply forward to the subexpression.
+ PrintExpr(Node->getSubExpr());
+}
+
void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
// No need to print anything, simply forward to the subexpression.
PrintExpr(Node->getSubExpr());
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 37c4d43ec0b2..65d1cdb7cf87 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1519,6 +1519,16 @@ void StmtProfiler::VisitCastExpr(const CastExpr *S) {
VisitExpr(S);
}
+void StmtProfiler::VisitConstantTemplateParamCastExpr(
+ const ConstantTemplateParamCastExpr *S) {
+ if (S->isDeduced()) {
+ Visit(S->getSubExpr());
+ } else {
+ VisitCastExpr(S);
+ VisitDecl(S->getParam());
+ }
+}
+
void StmtProfiler::VisitImplicitCastExpr(const ImplicitCastExpr *S) {
VisitCastExpr(S);
ID.AddInteger(S->getValueKind());
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 8f7fe3bea4e8..3b6c7f8613ef 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1534,6 +1534,14 @@ void TextNodeDumper::VisitImplicitCastExpr(const ImplicitCastExpr *Node) {
OS << " part_of_explicit_cast";
}
+void TextNodeDumper::VisitConstantTemplateParamCastExpr(
+ const ConstantTemplateParamCastExpr *Node) {
+ VisitCastExpr(Node);
+ if (Node->isDeduced())
+ OS << " is_deduced";
+ dumpDeclRef(Node->getParam());
+}
+
void TextNodeDumper::VisitDeclRefExpr(const DeclRefExpr *Node) {
OS << " ";
dumpBareDeclRef(Node->getDecl());
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 552c92996dc2..d384907f0ee3 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1312,6 +1312,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Expr::CStyleCastExprClass:
case Expr::CXXStaticCastExprClass:
case Expr::CXXFunctionalCastExprClass:
+ case Expr::ConstantTemplateParamCastExprClass:
case Expr::ImplicitCastExprClass:
case Expr::MaterializeTemporaryExprClass:
case Expr::UnaryOperatorClass: {
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index ea5c4265d736..b2a3da42257e 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -14744,10 +14744,13 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl);
if (Res.isInvalid())
return ExprError();
- return SemaRef.BuildResolvedCallExpr(
+ Res = SemaRef.BuildResolvedCallExpr(
Res.get(), FDecl, LParenLoc, Args, RParenLoc, ExecConfig,
/*IsExecConfig=*/false,
static_cast<CallExpr::ADLCallKind>((*Best)->IsADLCandidate));
+ if (Res.isInvalid())
+ return ExprError();
+ Fn = Res.get();
}
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index f051a246f954..b5b0cbcc680b 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5474,7 +5474,18 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
const TemplateArgument &Arg = ArgLoc.getArgument();
// Check non-type template parameters.
- if (NonTypeTemplateParmDecl *NTTP =dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (Arg.getKind() == TemplateArgument::Expression)
+ if (auto *E = dyn_cast<ConstantTemplateParamCastExpr>(Arg.getAsExpr());
+ E && E->getParam() == Param) {
+ // The argument is already converted for this parameter.
+ CTAI.SugaredConverted.push_back(
+ TemplateArgument(E, /*IsCanonical=*/false));
+ CTAI.CanonicalConverted.push_back(
+ TemplateArgument(E, /*IsCanonical=*/true));
+ return false;
+ }
+
// Do substitution on the type of the non-type template parameter
// with the template arguments we've seen thus far. But if the
// template has a dependent context then we cannot substitute yet.
@@ -5644,7 +5655,6 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc,
return false;
}
-
// Check template template parameters.
TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(Param);
@@ -7068,25 +7078,13 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType,
// If the parameter type somehow involves auto, deduce the type now.
DeducedType *DeducedT = ParamType->getContainedDeducedType();
+ bool IsDeduced = false;
if (getLangOpts().CPlusPlus17 && DeducedT && !DeducedT->isDeduced()) {
- // During template argument deduction, we allow 'decltype(auto)' to
- // match an arbitrary dependent argument.
- // FIXME: The language rules don't say what happens in this case.
- // FIXME: We get an opaque dependent type out of decltype(auto) if the
- // expression is merely instantiation-dependent; is this enough?
- if (DeductionArg->isTypeDependent()) {
- auto *AT = dyn_cast<AutoType>(DeducedT);
- if (AT && AT->isDecltypeAuto()) {
- SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
- CanonicalConverted = TemplateArgument(
- Context.getCanonicalTemplateArgument(SugaredConverted));
- return Arg;
- }
- }
-
- // When checking a deduced template argument, deduce from its type even if
- // the type is dependent, in order to check the types of non-type template
- // arguments line up properly in partial ordering.
+ IsDeduced = true;
+ // QualType UndeducedParamType = ParamType;
+ // When checking a deduced template argument, deduce from its type even if
+ // the type is dependent, in order to check the types of non-type template
+ // arguments line up properly in partial ordering.
TypeSourceInfo *TSI =
Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation());
if (isa<DeducedTemplateSpecializationType>(DeducedT)) {
@@ -7112,17 +7110,22 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType,
// along with the other associated constraints after
// checking the template argument list.
/*IgnoreConstraints=*/true);
- if (Result == TemplateDeductionResult::AlreadyDiagnosed) {
- return ExprError();
- } else if (Result != TemplateDeductionResult::Success) {
- if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
- Diag(Arg->getExprLoc(),
- diag::err_non_type_template_parm_type_deduction_failure)
- << Param->getDeclName() << NTTP->getType() << Arg->getType()
- << Arg->getSourceRange();
+ if (Result != TemplateDeductionResult::Success) {
+ ParamType = TSI->getType();
+ if (StrictCheck || !DeductionArg->isTypeDependent()) {
+ if (Result == TemplateDeductionResult::AlreadyDiagnosed)
+ return ExprError();
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
+ Diag(Arg->getExprLoc(),
+ diag::err_non_type_template_parm_type_deduction_failure)
+ << Param->getDeclName() << NTTP->getType() << Arg->getType()
+ << Arg->getSourceRange();
+ NoteTemplateParameterLocation(*Param);
+ return ExprError();
}
- NoteTemplateParameterLocation(*Param);
- return ExprError();
+ ParamType = SubstAutoTypeDependent(
+ ParamType, /*IsPack=*/isa<PackExpansionType>(ParamType));
+ assert(!ParamType.isNull() && "substituting DependentTy can't fail");
}
}
// CheckNonTypeTemplateParameterType will produce a diagnostic if there's
@@ -7144,14 +7147,11 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType,
// type-dependent, there's nothing we can check now.
if (ParamType->isDependentType() || DeductionArg->isTypeDependent()) {
// Force the argument to the type of the parameter to maintain invariants.
- ExprResult E = ImpCastExprToType(
- DeductionArg, ParamType.getNonLValueExprType(Context), CK_Dependent,
- ParamType->isLValueReferenceType() ? VK_LValue
- : ParamType->isRValueReferenceType() ? VK_XValue
- : VK_PRValue);
- if (E.isInvalid())
- return ExprError();
- setDeductionArg(E.get());
+ if (!Context.hasSameType(DeductionArg->getType(), ParamType))
+ DeductionArg = ConstantTemplateParamCastExpr::Create(
+ Context, cast<NonTypeTemplateParmDecl>(Param), ParamType,
+ DeductionArg, IsDeduced);
+ setDeductionArg(DeductionArg);
SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
CanonicalConverted = TemplateArgument(
Context.getCanonicalTemplateArgument(SugaredConverted));
@@ -8555,6 +8555,7 @@ static SourceRange findTemplateParameter(unsigned Depth, TypeLoc TL) {
static bool CheckNonTypeTemplatePartialSpecializationArgs(
Sema &S, SourceLocation TemplateNameLoc, NonTypeTemplateParmDecl *Param,
const TemplateArgument *Args, unsigned NumArgs, bool IsDefaultArgument) {
+ bool HasError = false;
for (unsigned I = 0; I != NumArgs; ++I) {
if (Args[I].getKind() == TemplateArgument::Pack) {
if (CheckNonTypeTemplatePartialSpecializationArgs(
@@ -8574,8 +8575,9 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs(
if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(ArgExpr))
ArgExpr = Expansion->getPattern();
- // Strip off any implicit casts we added as part of type checking.
- while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgExpr))
+ // Strip off any constant template parameter casts we added when checking
+ // the template argument.
+ while (auto *ICE = dyn_cast<ConstantTemplateParamCastExpr>(ArgExpr))
ArgExpr = ICE->getSubExpr();
// C++ [temp.class.spec]p8:
@@ -8595,6 +8597,11 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs(
continue;
}
+ if (isa<RecoveryExpr>(ArgExpr)) {
+ HasError = true;
+ continue;
+ }
+
// C++ [temp.class.spec]p9:
// Within the argument list of a class template partial
// specialization, the following restrictions apply:
@@ -8638,7 +8645,7 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs(
}
}
- return false;
+ return HasError;
}
bool Sema::CheckTemplatePartialSpecializationArgs(
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 62e867c44ad1..47bc57c166eb 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -153,6 +153,8 @@ static const Expr *unwrapExpressionForDeduction(const Expr *E) {
while (true) {
if (const auto *IC = dyn_cast<ImplicitCastExpr>(E))
E = IC->getSubExpr();
+ if (const auto *IC = dyn_cast<ConstantTemplateParamCastExpr>(E))
+ E = IC->getSubExpr();
else if (const auto *CE = dyn_cast<ConstantExpr>(E))
E = CE->getSubExpr();
else if (const auto *Subst = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
@@ -2659,12 +2661,13 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
// cast, in order to maintain invariants. Now we can deduce the
// resulting type from the original type, and deduce the original type
// against the parameter we are checking.
- if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E);
- ICE && ICE->getCastKind() == clang::CK_Dependent) {
- E = ICE->getSubExpr();
+ if (const auto *CE = dyn_cast<ConstantTemplateParamCastExpr>(E);
+ CE && !CE->isDeduced()) {
+ E = CE->getSubExpr();
+ assert(!isa<ConstantTemplateParamCastExpr>(E));
if (auto Result = DeduceTemplateArgumentsByTypeMatch(
- S, TemplateParams, ICE->getType(), E->getType(), Info,
- Deduced, TDF_SkipNonDependent,
+ S, TemplateParams, CE->getType(), E->getType(), Info, Deduced,
+ TDF_SkipNonDependent,
PartialOrdering ? PartialOrderingKind::NonCall
: PartialOrderingKind::None,
/*DeducedFromArrayBound=*/false, HasDeducedAnyParam);
@@ -5279,18 +5282,6 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
SmallVector<DeducedTemplateArgument, 1> Deduced;
Deduced.resize(1);
- // If deduction failed, don't diagnose if the initializer is dependent; it
- // might acquire a matching type in the instantiation.
- auto DeductionFailed = [&](TemplateDeductionResult TDK) {
- if (Init->isTypeDependent()) {
- Result =
- SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type);
- assert(!Result.isNull() && "substituting DependentTy can't fail");
- return TemplateDeductionResult::Success;
- }
- return TDK;
- };
-
SmallVector<OriginalCallArg, 4> OriginalCallArgs;
QualType DeducedType;
@@ -5340,9 +5331,9 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction)
<< Info.FirstArg << Info.SecondArg << DeducedFromInitRange
<< Init->getSourceRange();
- return DeductionFailed(TemplateDeductionResult::AlreadyDiagnosed);
+ return TemplateDeductionResult::AlreadyDiagnosed;
}
- return DeductionFailed(TDK);
+ return TDK;
}
if (DeducedFromInitRange.isInvalid() &&
@@ -5364,12 +5355,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
OriginalCallArgs,
/*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0, FailedTSC);
TDK != TemplateDeductionResult::Success)
- return DeductionFailed(TDK);
+ return TDK;
}
// Could be null if somehow 'auto' appears in a non-deduced context.
if (Deduced[0].getKind() != TemplateArgument::Type)
- return DeductionFailed(TemplateDeductionResult::Incomplete);
+ return TemplateDeductionResult::Incomplete;
DeducedType = Deduced[0].getAsType();
if (InitList) {
@@ -5383,7 +5374,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
if (!Context.hasSameType(DeducedType, Result)) {
Info.FirstArg = Result;
Info.SecondArg = DeducedType;
- return DeductionFailed(TemplateDeductionResult::Inconsistent);
+ return TemplateDeductionResult::Inconsistent;
}
DeducedType = Context.getCommonSugaredType(Result, DeducedType);
}
@@ -5407,7 +5398,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result,
CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA);
TDK != TemplateDeductionResult::Success) {
Result = QualType();
- return DeductionFailed(TDK);
+ return TDK;
}
}
@@ -5428,14 +5419,15 @@ TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto,
.TransformType(TypeWithAuto);
}
-QualType Sema::SubstAutoTypeDependent(QualType TypeWithAuto) {
- return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
+QualType Sema::SubstAutoTypeDependent(QualType TypeWithAuto, bool IsPack) {
+ return SubstituteDeducedTypeTransform(*this, DependentAuto{IsPack})
.TransformType(TypeWithAuto);
}
TypeSourceInfo *
-Sema::SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto) {
- return SubstituteDeducedTypeTransform(*this, DependentAuto{false})
+Sema::SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto,
+ bool IsPack) {
+ return SubstituteDeducedTypeTransform(*this, DependentAuto{IsPack})
.TransformType(TypeWithAuto);
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index a72c95d6d77c..6996437ab6b0 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -988,6 +988,11 @@ void Sema::PrintInstantiationStack(InstantiationContextDiagFuncRef DiagFunc) {
DiagFunc(Active->PointOfInstantiation,
PDiag(diag::note_template_class_instantiation_here)
<< CTD << Active->InstantiationRange);
+ } else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(D)) {
+ DiagFunc(
+ Active->PointOfInstantiation,
+ PDiag(diag::note_non_type_template_parameter_instantiation_here)
+ << NTTPD << Active->InstantiationRange);
}
break;
}
@@ -1644,9 +1649,7 @@ namespace {
ExprResult TransformTemplateParmRefExpr(DeclRefExpr *E,
NonTypeTemplateParmDecl *D);
ExprResult TransformSubstNonTypeTemplateParmPackExpr(
- SubstNonTypeTemplateParmPackExpr *E);
- ExprResult TransformSubstNonTypeTemplateParmExpr(
- SubstNonTypeTemplateParmExpr *E);
+ SubstNonTypeTemplateParmPackExpr *E);
/// Rebuild a DeclRefExpr for a VarDecl reference.
ExprResult RebuildVarDeclRefExpr(ValueDecl *PD, SourceLocation Loc);
@@ -2438,50 +2441,6 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr(
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);
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index adac3dff5b2b..e2dc70360506 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 242ffb09af00..006168af0ab0 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13650,6 +13650,43 @@ TreeTransform<Derived>::TransformConditionalOperator(ConditionalOperator *E) {
RHS.get());
}
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformConstantTemplateParamCastExpr(
+ ConstantTemplateParamCastExpr *E) {
+ ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr());
+ if (SubExpr.isInvalid())
+ return true;
+
+ auto *Param = cast_or_null<NonTypeTemplateParmDecl>(
+ getDerived().TransformDecl(E->getExprLoc(), E->getParam()));
+ if (!Param)
+ return true;
+
+ SourceLocation ParamLoc = Param->getLocation();
+
+ QualType ParamType =
+ E->isDeduced() ? Param->getType() : E->getParamType(SemaRef.Context);
+ if (!getDerived().AlreadyTransformed(ParamType)) {
+ Sema::InstantiatingTemplate Inst(SemaRef, getDerived().getBaseLocation(),
+ Param, E->getSourceRange());
+ TypeSourceInfo *DI =
+ E->isDeduced()
+ ? Param->getTypeSourceInfo()
+ : SemaRef.Context.getTrivialTypeSourceInfo(ParamType, ParamLoc);
+ TypeLocBuilder TLB;
+ ParamType = getDerived().TransformType(TLB, DI->getTypeLoc());
+ if (ParamType.isNull())
+ return true;
+ }
+ ParamType = SemaRef.CheckNonTypeTemplateParameterType(ParamType, ParamLoc);
+ if (ParamType.isNull())
+ return true;
+ TemplateArgument SugaredConverted, CanonicalConverted;
+ return SemaRef.CheckTemplateArgument(
+ Param, ParamType, SubExpr.get(), SugaredConverted, CanonicalConverted,
+ /*StrictCheck=*/false, Sema::CTAK_Specified);
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformImplicitCastExpr(ImplicitCastExpr *E) {
@@ -16297,12 +16334,27 @@ TreeTransform<Derived>::TransformSubstNonTypeTemplateParmPackExpr(
return E;
}
-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) {
+ ExprResult Res = getDerived().TransformExpr(E->getReplacement());
+ if (Res.isInvalid())
+ return true;
+ Expr *Replacement = Res.get();
+
+ Decl *AssociatedDecl =
+ getDerived().TransformDecl(E->getNameLoc(), E->getAssociatedDecl());
+ if (!AssociatedDecl)
+ return true;
+
+ if (Replacement == E->getReplacement() &&
+ AssociatedDecl == E->getAssociatedDecl())
+ return E;
+
+ return new (SemaRef.Context) SubstNonTypeTemplateParmExpr(
+ Replacement->getType(), Replacement->getValueKind(), E->getNameLoc(),
+ Replacement, AssociatedDecl, E->getIndex(), E->getPackIndex(),
+ E->isReferenceParameter(), E->getFinal());
}
template<typename Derived>
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 213c2c2148f6..3c3860407446 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1182,6 +1182,12 @@ ASTStmtReader::VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
E->ColonLoc = readSourceLocation();
}
+void ASTStmtReader::VisitConstantTemplateParamCastExpr(
+ ConstantTemplateParamCastExpr *E) {
+ VisitCastExpr(E);
+ E->Param = readDeclAs<NonTypeTemplateParmDecl>();
+}
+
void ASTStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) {
VisitCastExpr(E);
E->setIsPartOfExplicitCast(CurrentUnpackingBits->getNextBit());
@@ -3327,6 +3333,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}
+ case EXPR_CONSTANT_TEMPLATE_PARAM_CAST: {
+ S = ConstantTemplateParamCastExpr::CreateEmpty(Context);
+ break;
+ }
+
case EXPR_CSTYLE_CAST: {
unsigned PathSize = Record[ASTStmtReader::NumExprFields];
BitsUnpacker CastExprBits(Record[ASTStmtReader::NumExprFields + 1]);
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 21c04ddbc2c7..7785e602dce4 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1149,6 +1149,13 @@ void ASTStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
Code = serialization::EXPR_IMPLICIT_CAST;
}
+void ASTStmtWriter::VisitConstantTemplateParamCastExpr(
+ ConstantTemplateParamCastExpr *E) {
+ VisitCastExpr(E);
+ Record.AddDeclRef(E->getParam());
+ Code = serialization::EXPR_CONSTANT_TEMPLATE_PARAM_CAST;
+}
+
void ASTStmtWriter::VisitExplicitCastExpr(ExplicitCastExpr *E) {
VisitCastExpr(E);
Record.AddTypeSourceInfo(E->getTypeInfoAsWritten());
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 785cdfa15bf0..31ea7113a902 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -2280,6 +2280,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.addNodes(Dst);
break;
+ case Stmt::ConstantTemplateParamCastExprClass:
case Stmt::ImplicitCastExprClass:
case Stmt::CStyleCastExprClass:
case Stmt::CXXStaticCastExprClass:
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 1f4d44218ad1..2f1817d0ca7e 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/SemaCXX/delete-and-function-templates.cpp b/clang/test/SemaCXX/delete-and-function-templates.cpp
index b5854d3073c0..77ac9e9ac24d 100644
--- a/clang/test/SemaCXX/delete-and-function-templates.cpp
+++ b/clang/test/SemaCXX/delete-and-function-templates.cpp
@@ -12,7 +12,7 @@ namespace ns1 {
template<class T> double f(T) = delete; //expected-note{{candidate}}
char f(...); //expected-note{{candidate}}
-static_assert(is_same<decltype(f(3)),char>::value, ""); //expected-error{{call to deleted function}} expected-error{{static assertion failed}}
+static_assert(is_same<decltype(f(3)),char>::value, ""); //expected-error{{call to deleted function}}
template<class T> decltype(f(T{})) g(T); // this one sfinae's out.
template<class T> int *g(T);
diff --git a/clang/test/SemaTemplate/make_integer_seq.cpp b/clang/test/SemaTemplate/make_integer_seq.cpp
index 1203a5812b99..9354b007e947 100644
--- a/clang/test/SemaTemplate/make_integer_seq.cpp
+++ b/clang/test/SemaTemplate/make_integer_seq.cpp
@@ -80,7 +80,8 @@ template <template <class T, T...> class S, class T, int N> struct C {
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'T' dependent depth 0 index 1
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'T'
// CHECK-NEXT: `-TemplateArgument expr 'N'
-// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
+// CHECK-NEXT: `-ConstantTemplateParamCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
+// CHECK-NEXT: |-NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} depth 0 index 2 'type-parameter-0-1'
// CHECK-NEXT: `-DeclRefExpr 0x{{[0-9A-Fa-f]+}} <col:42> 'int' NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} 'N' 'int'
using test4 = __make_integer_seq<A, T, 1>;
@@ -94,7 +95,8 @@ template <template <class T, T...> class S, class T, int N> struct C {
// CHECK-NEXT: | `-TemplateTypeParmType 0x{{[0-9A-Fa-f]+}} 'T' dependent depth 0 index 1
// CHECK-NEXT: | `-TemplateTypeParm 0x{{[0-9A-Fa-f]+}} 'T'
// CHECK-NEXT: `-TemplateArgument expr '1'
-// CHECK-NEXT: `-ImplicitCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
+// CHECK-NEXT: `-ConstantTemplateParamCastExpr 0x{{[0-9A-Fa-f]+}} <line:{{.+}}:42> 'T' <Dependent>
+// CHECK-NEXT: |-NonTypeTemplateParm 0x{{[0-9A-Fa-f]+}} depth 0 index 2 'type-parameter-0-1'
// CHECK-NEXT: `-IntegerLiteral 0x{{[0-9A-Fa-f]+}} <col:42> 'int' 1
using test5 = __make_integer_seq<A, int, N>;
diff --git a/clang/test/SemaTemplate/temp_arg_nontype.cpp b/clang/test/SemaTemplate/temp_arg_nontype.cpp
index 7d2a010295b4..403018ccc5af 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype.cpp
@@ -498,7 +498,7 @@ namespace dependent_backreference {
int arr[sizeof(int)];
// When checking this template-id, we must not treat 'Value' as having type
// 'int'; its type is the dependent type 'T'.
- template<typename T> void f() { X<T, 0, &arr> x; } // expected-note {{substituting}}
+ template<typename T> void f() { X<T, 0, &arr> x; } // expected-note {{instantiation of non-type template parameter}}
void g() { f<short>(); }
void h() { f<int>(); } // expected-note {{instantiation}}
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp
index e74c031eba4c..d5dc2720b641 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 {{instantiation of non-type template parameter}}
+ template void g<int>();
+ // expected-note@-1 {{in instantiation of function template specialization}}
+}
diff --git a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
index d8a81bb36311..60d98a653ff0 100644
--- a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
+++ b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
@@ -83,11 +83,11 @@ namespace DependentType {
namespace Auto {
template<template<int> typename T> struct TInt {}; // #TInt
template<template<int*> typename T> struct TIntPtr {}; // #TIntPtr
- template<template<auto> typename T> struct TAuto {};
+ template<template<auto> typename T> struct TAuto {}; // #TAuto
template<template<auto*> typename T> struct TAutoPtr {};
- template<template<decltype(auto)> typename T> struct TDecltypeAuto {};
+ template<template<decltype(auto)> typename T> struct TDecltypeAuto {}; // #TDecltypeAuto
template<auto> struct Auto;
- template<auto*> struct AutoPtr; // #AutoPtr
+ template<auto*> struct AutoPtr;
template<decltype(auto)> struct DecltypeAuto;
template<int> struct Int;
template<int*> struct IntPtr;
@@ -108,7 +108,7 @@ namespace Auto {
TIntPtr<IntPtr> ipip;
TAuto<Auto> aa;
- TAuto<AutoPtr> aap; // expected-error@#AutoPtr {{could not match 'auto *' against 'auto'}}
+ TAuto<AutoPtr> aap; // expected-error@#TAuto {{non-type template parameter '' with type 'auto *' has incompatible initializer of type 'auto'}}
// expected-note@-1 {{different template parameters}}
TAuto<Int> ai; // FIXME: ill-formed (?)
TAuto<IntPtr> aip; // FIXME: ill-formed (?)
@@ -130,7 +130,7 @@ namespace Auto {
// parameters (such as 'user-defined-type &') that are not valid 'auto'
// parameters.
TDecltypeAuto<Auto> daa;
- TDecltypeAuto<AutoPtr> daap; // expected-error@#AutoPtr {{could not match 'auto *' against 'decltype(auto)'}}
+ TDecltypeAuto<AutoPtr> daap; // expected-error@#TDecltypeAuto {{non-type template parameter '' with type 'auto *' has incompatible initializer of type 'decltype(auto)'}}
// expected-note@-1 {{different template parameters}}
int n;
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index 3c4062410eac..8999e3589363 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -318,6 +318,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::ExpressionTraitExprClass:
case Stmt::ExtVectorElementExprClass:
case Stmt::ImplicitCastExprClass:
+ case Stmt::ConstantTemplateParamCastExprClass:
case Stmt::ImplicitValueInitExprClass:
case Stmt::NoInitExprClass:
case Stmt::MaterializeTemporaryExprClass: