[clang] WIP: implement ConstantTemplateParamCastExpr
This fixes a bunch of bugs with how non-type template parameters
are transformed and used in template argument deduction.
diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h
index c298f26..7abe33f 100644
--- a/clang/include/clang/AST/ComputeDependence.h
+++ b/clang/include/clang/AST/ComputeDependence.h
@@ -32,6 +32,7 @@
class CompoundLiteralExpr;
class ImplicitCastExpr;
class ExplicitCastExpr;
+class ConstantTemplateParamCastExpr;
class BinaryOperator;
class ConditionalOperator;
class BinaryConditionalOperator;
@@ -121,6 +122,7 @@
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 e1a4005..2667a94 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -3624,7 +3624,7 @@
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 @@
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 @@
*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 9fedb23..325744a 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4653,6 +4653,62 @@
}
};
+/// 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 427a9c5..7da9eb3 100644
--- a/clang/include/clang/AST/JSONNodeDumper.h
+++ b/clang/include/clang/AST/JSONNodeDumper.h
@@ -297,6 +297,8 @@
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 1d1b7f1..e88f90f 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2628,6 +2628,12 @@
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 76942f1a..0dd73f2 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -616,14 +616,17 @@
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 88ecd52..2df9124 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -271,6 +271,8 @@
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 bd89652..8237716 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5774,6 +5774,9 @@
"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 dd1a244..f1f0630 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -86,6 +86,7 @@
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 d017d1f..d409a0a 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -12683,11 +12683,11 @@
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 441047d..8fd9de2 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1684,6 +1684,9 @@
/// 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 e0cf0de..51ef1b4 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -157,6 +157,17 @@
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 f899b3c..727c89a 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3858,6 +3858,7 @@
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 97ae4a0..c5f3ae8 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1765,6 +1765,30 @@
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 aeacd0d..489584b 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -322,6 +322,7 @@
// 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 3b9ca82..da3bddd 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -18341,6 +18341,7 @@
}
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 2173aed..1e237db 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -5527,9 +5527,10 @@
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 0ef6328..3a50d1f 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -1459,6 +1459,12 @@
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 2c9c358..5eb5202 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1822,6 +1822,12 @@
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 37c4d43..65d1cdb 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1519,6 +1519,16 @@
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 8f7fe3b..3b6c7f8 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1534,6 +1534,14 @@
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 552c929..d384907 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1312,6 +1312,7 @@
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 ea5c426..b2a3da4 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -14744,10 +14744,13 @@
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 f051a24..b5b0cbc 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5474,7 +5474,18 @@
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 @@
return false;
}
-
// Check template template parameters.
TemplateTemplateParmDecl *TempParm = cast<TemplateTemplateParmDecl>(Param);
@@ -7068,25 +7078,13 @@
// 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 @@
// 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 @@
// 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 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 @@
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 @@
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 @@
}
}
- return false;
+ return HasError;
}
bool Sema::CheckTemplatePartialSpecializationArgs(
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 62e867c..47bc57c 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -153,6 +153,8 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA);
TDK != TemplateDeductionResult::Success) {
Result = QualType();
- return DeductionFailed(TDK);
+ return TDK;
}
}
@@ -5428,14 +5419,15 @@
.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 a72c95d..6996437 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -988,6 +988,11 @@
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 @@
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 @@
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 adac3df..e2dc703 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3742,7 +3742,7 @@
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 @@
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 @@
// 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..006168a 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13650,6 +13650,43 @@
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 @@
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 213c2c2..3c38604 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1182,6 +1182,12 @@
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 @@
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 21c04dd..7785e60 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1149,6 +1149,13 @@
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 785cdfa..31ea711 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -2280,6 +2280,7 @@
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 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 @@
// 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 b5854d3..77ac9e9 100644
--- a/clang/test/SemaCXX/delete-and-function-templates.cpp
+++ b/clang/test/SemaCXX/delete-and-function-templates.cpp
@@ -12,7 +12,7 @@
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 1203a58..9354b00 100644
--- a/clang/test/SemaTemplate/make_integer_seq.cpp
+++ b/clang/test/SemaTemplate/make_integer_seq.cpp
@@ -80,7 +80,8 @@
// 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 @@
// 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 7d2a010..403018c 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype.cpp
@@ -498,7 +498,7 @@
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 e74c031..d5dc272 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx2c.cpp
@@ -123,3 +123,14 @@
// 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 d8a81bb..60d98a6 100644
--- a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
+++ b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
@@ -83,11 +83,11 @@
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 @@
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 @@
// 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 3c40624..8999e35 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -318,6 +318,7 @@
case Stmt::ExpressionTraitExprClass:
case Stmt::ExtVectorElementExprClass:
case Stmt::ImplicitCastExprClass:
+ case Stmt::ConstantTemplateParamCastExprClass:
case Stmt::ImplicitValueInitExprClass:
case Stmt::NoInitExprClass:
case Stmt::MaterializeTemporaryExprClass: