https://github.com/mizvekov created 
https://github.com/llvm/llvm-project/pull/160018

This fixes a bunch of bugs with how non-type template parameters are 
transformed and used in template argument deduction.

>From a0db4a10c306786d3ab689c4094a2676c18f2c53 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizve...@gmail.com>
Date: Mon, 15 Sep 2025 01:58:01 -0300
Subject: [PATCH] [clang] WIP: implement ConstantTemplateParamCastExpr

This fixes a bunch of bugs with how non-type template parameters
are transformed and used in template argument deduction.
---
 clang/include/clang/AST/ComputeDependence.h   |  2 +
 clang/include/clang/AST/Expr.h                |  8 +-
 clang/include/clang/AST/ExprCXX.h             | 56 ++++++++++++
 clang/include/clang/AST/JSONNodeDumper.h      |  2 +
 clang/include/clang/AST/RecursiveASTVisitor.h |  6 ++
 clang/include/clang/AST/Stmt.h                |  5 +-
 clang/include/clang/AST/TextNodeDumper.h      |  2 +
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 +
 clang/include/clang/Basic/StmtNodes.td        |  1 +
 clang/include/clang/Sema/Sema.h               |  6 +-
 .../include/clang/Serialization/ASTBitCodes.h |  3 +
 clang/lib/AST/ComputeDependence.cpp           | 11 +++
 clang/lib/AST/Expr.cpp                        |  1 +
 clang/lib/AST/ExprCXX.cpp                     | 24 +++++
 clang/lib/AST/ExprClassification.cpp          |  1 +
 clang/lib/AST/ExprConstant.cpp                |  1 +
 clang/lib/AST/ItaniumMangle.cpp               |  3 +-
 clang/lib/AST/JSONNodeDumper.cpp              |  6 ++
 clang/lib/AST/StmtPrinter.cpp                 |  6 ++
 clang/lib/AST/StmtProfile.cpp                 | 10 +++
 clang/lib/AST/TextNodeDumper.cpp              |  8 ++
 clang/lib/Sema/SemaExceptionSpec.cpp          |  1 +
 clang/lib/Sema/SemaOverload.cpp               |  5 +-
 clang/lib/Sema/SemaTemplate.cpp               | 89 ++++++++++---------
 clang/lib/Sema/SemaTemplateDeduction.cpp      | 46 ++++------
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 53 ++---------
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 23 +++--
 clang/lib/Sema/TreeTransform.h                | 64 +++++++++++--
 clang/lib/Serialization/ASTReaderStmt.cpp     | 11 +++
 clang/lib/Serialization/ASTWriterStmt.cpp     |  7 ++
 clang/lib/StaticAnalyzer/Core/ExprEngine.cpp  |  1 +
 clang/test/SemaCXX/cxx20-ctad-type-alias.cpp  |  2 +-
 .../SemaCXX/delete-and-function-templates.cpp |  2 +-
 clang/test/SemaTemplate/make_integer_seq.cpp  |  6 +-
 clang/test/SemaTemplate/temp_arg_nontype.cpp  |  2 +-
 .../SemaTemplate/temp_arg_nontype_cxx2c.cpp   | 11 +++
 .../SemaTemplate/temp_arg_template_p0522.cpp  | 10 +--
 clang/tools/libclang/CXCursor.cpp             |  1 +
 38 files changed, 345 insertions(+), 154 deletions(-)

diff --git a/clang/include/clang/AST/ComputeDependence.h 
b/clang/include/clang/AST/ComputeDependence.h
index c298f2620f211..7abe33f4d6db7 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 e1a4005d1a890..2667a942479cb 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -3624,7 +3624,7 @@ class CastExpr : public Expr {
            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 @@ class CastExpr : public Expr {
   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 @@ class ImplicitCastExpr final
       *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 9fedb230ce397..325744a649407 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -4653,6 +4653,62 @@ class PackIndexingExpr final
   }
 };
 
+/// 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 427a9c51ece1b..7da9eb3f35d36 100644
--- a/clang/include/clang/AST/JSONNodeDumper.h
+++ b/clang/include/clang/AST/JSONNodeDumper.h
@@ -297,6 +297,8 @@ class JSONNodeDumper
   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 1d1b7f183f75a..e88f90ff8ed55 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 76942f1a84f9a..0dd73f28327bf 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -616,14 +616,17 @@ class alignas(void *) Stmt {
   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 88ecd526e3d7e..2df912479568b 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -271,6 +271,8 @@ class TextNodeDumper
   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 bd896524321d1..823771657c531 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 dd1a24405fae7..f1f063068c728 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 d017d1f829015..d409a0a09bed8 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -12683,11 +12683,11 @@ class Sema final : public SemaBase {
                                           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 441047d64f48c..8fd9de20c9b77 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 e0cf0deb12bd2..51ef1b4ffb308 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 f899b3c4bb79c..727c89ad8b734 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 97ae4a07f32aa..c5f3ae8c17b83 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 aeacd0dc765ef..489584bb3ebf9 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 3b9ca82910033..da3bdddfa59a3 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 2173aed5b45af..1e237dbb29e61 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -5527,9 +5527,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, 
unsigned Arity,
     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 0ef632805d67c..3a50d1fc493d1 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 2c9c3581a2962..5eb5202138686 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 37c4d43ec0b2f..65d1cdb7cf87b 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 8f7fe3bea4e8f..3b6c7f8613efb 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 552c92996dc2e..d384907f0ee3a 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 ea5c4265d736d..b2a3da42257e6 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 f051a246f954f..b5b0cbcc680b8 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 62e867c44ad14..47bc57c166ebc 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 a72c95d6d77cf..6996437ab6b0e 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 adac3dff5b2b4..e2dc70360506e 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 242ffb09af006..006168af0ab0e 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 213c2c2148f64..3c3860407446b 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 21c04ddbc2c7a..7785e602dce48 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 785cdfa15bf04..31ea7113a9021 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 1f4d44218ad1f..2f1817d0ca7eb 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 b5854d3073c03..77ac9e9ac24dd 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 1203a5812b991..9354b007e9475 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 7d2a010295b47..403018ccc5afe 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 e74c031eba4c1..d5dc2720b6413 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 d8a81bb363112..60d98a653ff02 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 3c4062410eac1..8999e3589363d 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:

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to