https://github.com/mizvekov updated 
https://github.com/llvm/llvm-project/pull/207865

>From 2e7bd77c557098165a7153f69b217dfe5661e313 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <[email protected]>
Date: Sat, 4 Apr 2026 20:44:35 -0300
Subject: [PATCH] trivial changes

---
 .../clang-tidy/modernize/LoopConvertUtils.cpp |  4 +--
 .../clang-tidy/utils/ASTUtils.cpp             |  7 ++--
 clang-tools-extra/clangd/AST.cpp              |  6 +++-
 clang-tools-extra/clangd/InlayHints.cpp       |  2 +-
 clang/include/clang/AST/ASTContext.h          | 10 +++---
 clang/include/clang/AST/DeclTemplate.h        | 15 ++++----
 clang/include/clang/AST/PropertiesBase.td     |  6 ++--
 clang/include/clang/AST/RecursiveASTVisitor.h |  5 ++-
 clang/include/clang/AST/TemplateBase.h        |  9 ++---
 clang/include/clang/AST/TypeLoc.h             |  5 ++-
 .../clang/Serialization/ASTRecordReader.h     | 17 ++++++----
 .../clang/Serialization/ASTRecordWriter.h     |  4 +++
 clang/lib/AST/ASTContext.cpp                  | 32 +++++++++--------
 clang/lib/AST/ASTDiagnostic.cpp               | 22 +++++++-----
 clang/lib/AST/ASTImporter.cpp                 |  5 ++-
 clang/lib/AST/AttrImpl.cpp                    |  2 +-
 clang/lib/AST/DeclTemplate.cpp                | 11 +++---
 clang/lib/AST/JSONNodeDumper.cpp              | 12 +++++--
 clang/lib/AST/ODRHash.cpp                     |  4 ---
 clang/lib/AST/StmtProfile.cpp                 |  6 ++--
 clang/lib/AST/TemplateBase.cpp                |  6 ++--
 clang/lib/AST/TemplateName.cpp                |  7 +---
 clang/lib/AST/TextNodeDumper.cpp              | 25 ++++++++++++--
 clang/lib/AST/Type.cpp                        | 25 ++++++++------
 clang/lib/AST/TypePrinter.cpp                 |  3 +-
 .../Frontend/Rewrite/RewriteModernObjC.cpp    |  6 ++--
 clang/lib/Sema/SemaCXXScopeSpec.cpp           |  1 +
 clang/lib/Sema/SemaChecking.cpp               |  4 +--
 clang/lib/Sema/SemaConcept.cpp                |  2 +-
 clang/lib/Sema/SemaExpr.cpp                   |  2 +-
 clang/lib/Sema/SemaExprCXX.cpp                |  1 +
 clang/lib/Sema/SemaLookup.cpp                 |  3 +-
 clang/lib/Sema/SemaOpenACCAtomic.cpp          |  6 ++--
 clang/lib/Sema/SemaOpenMP.cpp                 | 34 +++++++++++--------
 clang/lib/Sema/SemaTemplate.cpp               | 31 +++++++++--------
 clang/lib/Sema/SemaTemplateDeduction.cpp      | 16 +++++----
 clang/lib/Sema/SemaType.cpp                   |  4 ++-
 clang/lib/Sema/TreeTransform.h                | 16 ++++-----
 clang/lib/Serialization/ASTReader.cpp         |  7 ++--
 clang/lib/Serialization/ASTReaderDecl.cpp     |  9 ++---
 clang/lib/Serialization/ASTWriter.cpp         |  1 +
 41 files changed, 231 insertions(+), 162 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp 
b/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp
index ae97a7e0a0266..9f0d62432e4e9 100644
--- a/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertUtils.cpp
@@ -231,7 +231,7 @@ template <typename ContainerT>
 static bool containsExpr(ASTContext *Context, const ContainerT *Container,
                          const Expr *E) {
   llvm::FoldingSetNodeID ID;
-  E->Profile(ID, *Context, true);
+  E->Profile(ID, *Context, CanonicalizationKind::Structural);
   return llvm::any_of(*Container,
                       [&](const auto &I) { return ID == I.second; });
 }
@@ -470,7 +470,7 @@ void ForLoopIndexUseVisitor::addComponents(const 
ComponentVector &Components) {
 void ForLoopIndexUseVisitor::addComponent(const Expr *E) {
   llvm::FoldingSetNodeID ID;
   const Expr *Node = E->IgnoreParenImpCasts();
-  Node->Profile(ID, *Context, true);
+  Node->Profile(ID, *Context, CanonicalizationKind::Structural);
   DependentExprs.emplace_back(Node, ID);
 }
 
diff --git a/clang-tools-extra/clang-tidy/utils/ASTUtils.cpp 
b/clang-tools-extra/clang-tidy/utils/ASTUtils.cpp
index 4baef7539008a..d01f15512ff6f 100644
--- a/clang-tools-extra/clang-tidy/utils/ASTUtils.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ASTUtils.cpp
@@ -106,8 +106,11 @@ bool areStatementsIdentical(const Stmt *FirstStmt, const 
Stmt *SecondStmt,
   }
 
   llvm::FoldingSetNodeID DataFirst, DataSecond;
-  FirstStmt->Profile(DataFirst, Context, Canonical);
-  SecondStmt->Profile(DataSecond, Context, Canonical);
+  auto CanonKind =
+      Canonical ? CanonicalizationKindOrNone(CanonicalizationKind::Structural)
+                : std::nullopt;
+  FirstStmt->Profile(DataFirst, Context, CanonKind);
+  SecondStmt->Profile(DataSecond, Context, CanonKind);
   return DataFirst == DataSecond;
 }
 
diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp
index 046bec5d0d5e6..378e3ae40f475 100644
--- a/clang-tools-extra/clangd/AST.cpp
+++ b/clang-tools-extra/clangd/AST.cpp
@@ -562,8 +562,12 @@ class DeducedTypeVisitor : public 
RecursiveASTVisitor<DeducedTypeVisitor> {
     //  decltype(I) J = I;
     //  decltype(J) K = J;
     const DecltypeType *DT = dyn_cast<DecltypeType>(TL.getTypePtr());
-    while (DT && !DT->getUnderlyingType().isNull()) {
+    while (DT) {
       DeducedType = DT->getUnderlyingType();
+      if (DeducedType.isNull()) {
+        DeducedType = DT->getUnderlyingExpr()->getType();
+        break;
+      }
       DT = dyn_cast<DecltypeType>(DeducedType.getTypePtr());
     }
     return true;
diff --git a/clang-tools-extra/clangd/InlayHints.cpp 
b/clang-tools-extra/clangd/InlayHints.cpp
index 5bae4cc040210..4fb32f26c17de 100644
--- a/clang-tools-extra/clangd/InlayHints.cpp
+++ b/clang-tools-extra/clangd/InlayHints.cpp
@@ -400,7 +400,7 @@ class InlayHintVisitor : public 
RecursiveASTVisitor<InlayHintVisitor> {
 
   bool VisitTypeLoc(TypeLoc TL) {
     if (const auto *DT = llvm::dyn_cast<DecltypeType>(TL.getType()))
-      if (QualType UT = DT->getUnderlyingType(); !UT->isDependentType())
+      if (QualType UT = DT->getUnderlyingType(); !UT.isNull())
         addTypeHint(TL.getSourceRange(), UT, ": ");
     return true;
   }
diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index 96f778720474f..00268227b7a50 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -253,8 +253,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
     FunctionProtoTypes;
   mutable llvm::ContextualFoldingSet<DependentTypeOfExprType, ASTContext &>
       DependentTypeOfExprTypes;
-  mutable llvm::ContextualFoldingSet<DependentDecltypeType, ASTContext &>
-      DependentDecltypeTypes;
+  mutable llvm::ContextualFoldingSet<DecltypeType, ASTContext &> DecltypeTypes;
 
   mutable llvm::ContextualFoldingSet<PackIndexingType, ASTContext &>
       DependentPackIndexingTypes;
@@ -2020,9 +2019,10 @@ class ASTContext : public RefCountedBase<ASTContext> {
                                         Decl *AssociatedDecl, unsigned Index,
                                         UnsignedOrNone PackIndex,
                                         bool Final) const;
-  QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
-                                            unsigned Index, bool Final,
-                                            const TemplateArgument &ArgPack);
+  QualType
+  getSubstTemplateTypeParmPackType(Decl *AssociatedDecl, unsigned Index,
+                                   bool Final,
+                                   const TemplateArgument &ArgPack) const;
   QualType getSubstBuiltinTemplatePack(const TemplateArgument &ArgPack);
 
   QualType
diff --git a/clang/include/clang/AST/DeclTemplate.h 
b/clang/include/clang/AST/DeclTemplate.h
index 672648c3fc03c..76abe06fa6354 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -2128,7 +2128,6 @@ class ClassTemplatePartialSpecializationDecl
       SourceLocation IdLoc, TemplateParameterList *Params,
       const ASTTemplateArgumentListInfo *ArgsAsWritten,
       ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
-      CanQualType CanonInjectedTST,
       ClassTemplatePartialSpecializationDecl *PrevDecl);
 
   ClassTemplatePartialSpecializationDecl(ASTContext &C)
@@ -2141,14 +2140,12 @@ class ClassTemplatePartialSpecializationDecl
   friend class ASTDeclReader;
   friend class ASTDeclWriter;
 
-  static ClassTemplatePartialSpecializationDecl *
-  Create(ASTContext &Context, TagKind TK, DeclContext *DC,
-         SourceLocation StartLoc, SourceLocation IdLoc,
-         TemplateParameterList *Params,
-         const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
-         ClassTemplateDecl *SpecializedTemplate,
-         ArrayRef<TemplateArgument> Args, CanQualType CanonInjectedTST,
-         ClassTemplatePartialSpecializationDecl *PrevDecl);
+  static ClassTemplatePartialSpecializationDecl *Create(
+      ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation 
StartLoc,
+      SourceLocation IdLoc, TemplateParameterList *Params,
+      const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
+      ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
+      ClassTemplatePartialSpecializationDecl *PrevDecl);
 
   static ClassTemplatePartialSpecializationDecl *
   CreateDeserialized(ASTContext &C, GlobalDeclID ID);
diff --git a/clang/include/clang/AST/PropertiesBase.td 
b/clang/include/clang/AST/PropertiesBase.td
index 4cfda71873383..5b8e72739702b 100644
--- a/clang/include/clang/AST/PropertiesBase.td
+++ b/clang/include/clang/AST/PropertiesBase.td
@@ -906,14 +906,14 @@ let Class = PropertyTypeCase<TemplateArgument, 
"Expression"> in {
   def : Property<"expression", ExprRef> {
     let Read = [{ node.getAsExpr() }];
   }
-  def : Property<"IsCanonical", Bool> {
-    let Read = [{ node.isCanonicalExpr() }];
+  def : Property<"CanonKind", CanonicalizationKindOrNone> {
+    let Read = [{ node.getExprCanonKind() }];
   }
   def : Property<"isDefaulted", Bool> {
     let Read = [{ node.getIsDefaulted() }];
   }
   def : Creator<[{
-    return TemplateArgument(expression, IsCanonical, isDefaulted);
+    return TemplateArgument(expression, CanonKind, isDefaulted);
   }]>;
 }
 let Class = PropertyTypeCase<TemplateArgument, "Pack"> in {
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h 
b/clang/include/clang/AST/RecursiveASTVisitor.h
index 222dbf5559e12..dc0a8084bcf05 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1466,9 +1466,8 @@ DEF_TRAVERSE_TYPELOC(TypeOfType, {
 })
 
 // FIXME: location of underlying expr
-DEF_TRAVERSE_TYPELOC(DecltypeType, {
-  TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr()));
-})
+DEF_TRAVERSE_TYPELOC(DecltypeType,
+                     { TRY_TO(TraverseStmt(TL.getUnderlyingExpr())); })
 
 DEF_TRAVERSE_TYPELOC(PackIndexingType, {
   TRY_TO(TraverseType(TL.getPattern()));
diff --git a/clang/include/clang/AST/TemplateBase.h 
b/clang/include/clang/AST/TemplateBase.h
index 5d4723045f208..9e00469e6a8bf 100644
--- a/clang/include/clang/AST/TemplateBase.h
+++ b/clang/include/clang/AST/TemplateBase.h
@@ -167,8 +167,8 @@ class TemplateArgument {
     unsigned Kind : 31;
     LLVM_PREFERRED_TYPE(bool)
     unsigned IsDefaulted : 1;
-    LLVM_PREFERRED_TYPE(bool)
-    unsigned IsCanonicalExpr : 1;
+    LLVM_PREFERRED_TYPE(CanonicalizationKindOrNone)
+    unsigned ExprCanonKind : 2;
     uintptr_t V;
   };
   union {
@@ -269,10 +269,11 @@ class TemplateArgument {
   /// This form of template argument only occurs in template argument
   /// lists used for dependent types and for expression; it will not
   /// occur in a non-dependent, canonical template argument list.
-  TemplateArgument(Expr *E, bool IsCanonical, bool IsDefaulted = false) {
+  TemplateArgument(Expr *E, CanonicalizationKindOrNone CanonKind,
+                   bool IsDefaulted = false) {
     TypeOrValue.Kind = Expression;
     TypeOrValue.IsDefaulted = IsDefaulted;
-    TypeOrValue.IsCanonicalExpr = IsCanonical;
+    TypeOrValue.ExprCanonKind = CanonKind.toInternalRepresentation();
     TypeOrValue.V = reinterpret_cast<uintptr_t>(E);
   }
 
diff --git a/clang/include/clang/AST/TypeLoc.h 
b/clang/include/clang/AST/TypeLoc.h
index 24df18dbaace4..92c099b474956 100644
--- a/clang/include/clang/AST/TypeLoc.h
+++ b/clang/include/clang/AST/TypeLoc.h
@@ -2275,6 +2275,7 @@ class TypeOfTypeLoc
 // FIXME: add LParenLoc, it is tricky to support due to the limitation of
 // annotated-decltype token.
 struct DecltypeTypeLocInfo {
+  Expr *UnderlyingExpr;
   SourceLocation DecltypeLoc;
   SourceLocation RParenLoc;
 };
@@ -2282,7 +2283,8 @@ class DecltypeTypeLoc
     : public ConcreteTypeLoc<UnqualTypeLoc, DecltypeTypeLoc, DecltypeType,
                              DecltypeTypeLocInfo> {
 public:
-  Expr *getUnderlyingExpr() const { return getTypePtr()->getUnderlyingExpr(); }
+  Expr *getUnderlyingExpr() const { return getLocalData()->UnderlyingExpr; }
+  void setUnderlyingExpr(Expr *E) { getLocalData()->UnderlyingExpr = E; }
 
   SourceLocation getDecltypeLoc() const { return getLocalData()->DecltypeLoc; }
   void setDecltypeLoc(SourceLocation Loc) { getLocalData()->DecltypeLoc = Loc; 
}
@@ -2295,6 +2297,7 @@ class DecltypeTypeLoc
   }
 
   void initializeLocal(ASTContext &Context, SourceLocation Loc) {
+    setUnderlyingExpr(getTypePtr()->getUnderlyingExpr());
     setDecltypeLoc(Loc);
     setRParenLoc(Loc);
   }
diff --git a/clang/include/clang/Serialization/ASTRecordReader.h 
b/clang/include/clang/Serialization/ASTRecordReader.h
index aed1b7d309001..caba5917721cb 100644
--- a/clang/include/clang/Serialization/ASTRecordReader.h
+++ b/clang/include/clang/Serialization/ASTRecordReader.h
@@ -233,11 +233,10 @@ class ASTRecordReader
   /// Read a template argument, advancing Idx. (inherited)
   // TemplateArgument readTemplateArgument();
   using DataStreamBasicReader::readTemplateArgument;
-  TemplateArgument readTemplateArgument(bool Canonicalize) {
+  TemplateArgument readTemplateArgument(CanonicalizationKindOrNone CanonKind) {
     TemplateArgument Arg = readTemplateArgument();
-    if (Canonicalize) {
-      Arg = getContext().getCanonicalTemplateArgument(Arg);
-    }
+    if (CanonKind)
+      Arg = getContext().getCanonicalTemplateArgument(Arg, *CanonKind);
     return Arg;
   }
 
@@ -245,8 +244,9 @@ class ASTRecordReader
   TemplateParameterList *readTemplateParameterList();
 
   /// Read a template argument array, advancing Idx.
-  void readTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs,
-                                bool Canonicalize = false);
+  void
+  readTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs,
+                           CanonicalizationKindOrNone CanonKind = 
std::nullopt);
 
   /// Read a UnresolvedSet structure, advancing Idx.
   void readUnresolvedSet(LazyASTUnresolvedSet &Set);
@@ -324,6 +324,11 @@ class ASTRecordReader
     return UnsignedOrNone::fromInternalRepresentation(unsigned(readInt()));
   }
 
+  CanonicalizationKindOrNone readCanonicalizationKindOrNone() {
+    return CanonicalizationKindOrNone::fromInternalRepresentation(
+        unsigned(readInt()));
+  }
+
   /// Read a string, advancing Idx.
   std::string readString() {
     return Reader->ReadString(Record, Idx);
diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h 
b/clang/include/clang/Serialization/ASTRecordWriter.h
index 9849ea6b395ab..43e09d1682622 100644
--- a/clang/include/clang/Serialization/ASTRecordWriter.h
+++ b/clang/include/clang/Serialization/ASTRecordWriter.h
@@ -193,6 +193,10 @@ class ASTRecordWriter
     Record->push_back(Value.toInternalRepresentation());
   }
 
+  void writeCanonicalizationKindOrNone(CanonicalizationKindOrNone Value) {
+    Record->push_back(Value.toInternalRepresentation());
+  }
+
   /// Emit an integral value.
   void AddAPInt(const llvm::APInt &Value) {
     writeAPInt(Value);
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index e238e7fece16a..bf1ba2d6846cf 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -935,7 +935,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager 
&SM,
       DependentAddressSpaceTypes(this_()), DependentVectorTypes(this_()),
       DependentSizedMatrixTypes(this_()),
       FunctionProtoTypes(this_(), FunctionProtoTypesLog2InitSize),
-      DependentTypeOfExprTypes(this_()), DependentDecltypeTypes(this_()),
+      DependentTypeOfExprTypes(this_()), DecltypeTypes(this_()),
       DependentPackIndexingTypes(this_()), 
TemplateSpecializationTypes(this_()),
       AttributedTypes(this_()), DependentBitIntTypes(this_()),
       SubstTemplateTemplateParmPacks(this_()), DeducedTemplates(this_()),
@@ -5978,10 +5978,9 @@ QualType 
ASTContext::getSubstTemplateTypeParmType(QualType Replacement,
   return QualType(SubstParm, 0);
 }
 
-QualType
-ASTContext::getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
-                                             unsigned Index, bool Final,
-                                             const TemplateArgument &ArgPack) {
+QualType ASTContext::getSubstTemplateTypeParmPackType(
+    Decl *AssociatedDecl, unsigned Index, bool Final,
+    const TemplateArgument &ArgPack) const {
 #ifndef NDEBUG
   for (const auto &P : ArgPack.pack_elements())
     assert(P.getKind() == TemplateArgument::Type && "Pack contains a 
non-type");
@@ -6347,7 +6346,7 @@ TemplateArgument 
ASTContext::getInjectedTemplateArg(NamedDecl *Param) const {
 
     if (NTTP->isParameterPack())
       E = new (*this) PackExpansionExpr(E, NTTP->getLocation(), std::nullopt);
-    Arg = TemplateArgument(E, /*IsCanonical=*/false);
+    Arg = TemplateArgument(E, /*CanonKind=*/std::nullopt);
   } else {
     auto *TTP = cast<TemplateTemplateParmDecl>(Param);
     TemplateName Name = getQualifiedTemplateName(
@@ -7631,8 +7630,10 @@ bool ASTContext::isSameConstraintExpr(const Expr *XCE, 
const Expr *YCE) const {
     return true;
 
   llvm::FoldingSetNodeID XCEID, YCEID;
-  XCE->Profile(XCEID, *this, /*Canonical=*/true, /*ProfileLambdaExpr=*/true);
-  YCE->Profile(YCEID, *this, /*Canonical=*/true, /*ProfileLambdaExpr=*/true);
+  XCE->Profile(XCEID, *this, CanonicalizationKind::Functional,
+               /*ProfileLambdaExpr=*/true);
+  YCE->Profile(YCEID, *this, CanonicalizationKind::Functional,
+               /*ProfileLambdaExpr=*/true);
   return XCEID == YCEID;
 }
 
@@ -7744,9 +7745,10 @@ bool ASTContext::isSameDefaultTemplateArgument(const 
NamedDecl *X,
         
NTTPX->getDefaultArgument().getArgument().getAsExpr()->IgnoreImpCasts();
     Expr *DefaultArgumentY =
         
NTTPY->getDefaultArgument().getArgument().getAsExpr()->IgnoreImpCasts();
+    // FIXME: This should probably use functional equivalence instead.
     llvm::FoldingSetNodeID XID, YID;
-    DefaultArgumentX->Profile(XID, *this, /*Canonical=*/true);
-    DefaultArgumentY->Profile(YID, *this, /*Canonical=*/true);
+    DefaultArgumentX->Profile(XID, *this, CanonicalizationKind::Structural);
+    DefaultArgumentY->Profile(YID, *this, CanonicalizationKind::Structural);
     return XID == YID;
   }
 
@@ -7829,8 +7831,10 @@ static bool hasSameOverloadableAttrs(const FunctionDecl 
*A,
     Cand1ID.clear();
     Cand2ID.clear();
 
-    (*Cand1A)->getCond()->Profile(Cand1ID, A->getASTContext(), true);
-    (*Cand2A)->getCond()->Profile(Cand2ID, B->getASTContext(), true);
+    (*Cand1A)->getCond()->Profile(Cand1ID, A->getASTContext(),
+                                  CanonicalizationKind::Structural);
+    (*Cand2A)->getCond()->Profile(Cand2ID, B->getASTContext(),
+                                  CanonicalizationKind::Structural);
 
     // Return false if any of the enable_if expressions of A and B are
     // different.
@@ -8191,8 +8195,8 @@ bool ASTContext::isSameTemplateArgument(const 
TemplateArgument &Arg1,
 
   case TemplateArgument::Expression: {
     llvm::FoldingSetNodeID ID1, ID2;
-    Arg1.getAsExpr()->Profile(ID1, *this, /*Canonical=*/true);
-    Arg2.getAsExpr()->Profile(ID2, *this, /*Canonical=*/true);
+    Arg1.getAsExpr()->Profile(ID1, *this, CanonicalizationKind::Structural);
+    Arg2.getAsExpr()->Profile(ID2, *this, CanonicalizationKind::Structural);
     return ID1 == ID2;
   }
 
diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp
index f7888f58985db..33593f12be07b 100644
--- a/clang/lib/AST/ASTDiagnostic.cpp
+++ b/clang/lib/AST/ASTDiagnostic.cpp
@@ -126,7 +126,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, 
QualType QT,
           ShouldAKA = true;
           QT = Context.getTemplateSpecializationType(
               TST->getKeyword(), TST->getTemplateName(), Args,
-              /*CanonicalArgs=*/{}, QT);
+              /*CanonicalArgs=*/{}, QT.getCanonicalType());
         }
         break;
       }
@@ -1534,8 +1534,8 @@ class TemplateDiff {
       return false;
 
     llvm::FoldingSetNodeID FromID, ToID;
-    FromExpr->Profile(FromID, Context, true);
-    ToExpr->Profile(ToID, Context, true);
+    FromExpr->Profile(FromID, Context, CanonicalizationKind::Structural);
+    ToExpr->Profile(ToID, Context, CanonicalizationKind::Structural);
     return FromID == ToID;
   }
 
@@ -2149,15 +2149,21 @@ class TemplateDiff {
       return;
     }
 
+    TemplateDecl *FromOrigTD = 
FromOrigTST->getTemplateName().getAsTemplateDecl(
+        /*IgnoreDeduced=*/true);
+    TemplateDecl *ToOrigTD = ToOrigTST->getTemplateName().getAsTemplateDecl(
+        /*IgnoreDeduced=*/true);
+    // If either side does not have a template declaration, then there are no
+    // template parameters, and nothing further to diff.
+    if (!FromOrigTD || !ToOrigTD)
+      return;
+
     FromQual -= QualType(FromOrigTST, 0).getQualifiers();
     ToQual -= QualType(ToOrigTST, 0).getQualifiers();
 
     // Same base template, but different arguments.
-    Tree.SetTemplateDiff(
-        FromOrigTST->getTemplateName().getAsTemplateDecl(
-            /*IgnoreDeduced=*/true),
-        ToOrigTST->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true),
-        FromQual, ToQual, false /*FromDefault*/, false /*ToDefault*/);
+    Tree.SetTemplateDiff(FromOrigTD, ToOrigTD, FromQual, ToQual,
+                         false /*FromDefault*/, false /*ToDefault*/);
 
     DiffTemplate(FromOrigTST, ToOrigTST);
   }
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 08751f02ec36d..55223a4a945c4 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -917,7 +917,7 @@ ASTNodeImporter::import(const TemplateArgument &From) {
 
   case TemplateArgument::Expression:
     if (ExpectedExpr ToExpr = import(From.getAsExpr()))
-      return TemplateArgument(*ToExpr, From.isCanonicalExpr(),
+      return TemplateArgument(*ToExpr, From.getExprCanonKind(),
                               From.getIsDefaulted());
     else
       return ToExpr.takeError();
@@ -1723,7 +1723,7 @@ ExpectedType ASTNodeImporter::VisitDecltypeType(const 
DecltypeType *T) {
     return ToUnderlyingTypeOrErr.takeError();
 
   return Importer.getToContext().getDecltypeType(
-      *ToExprOrErr, *ToUnderlyingTypeOrErr);
+      *ToExprOrErr, T->getExprCanonicalizationKind(), *ToUnderlyingTypeOrErr);
 }
 
 ExpectedType
@@ -6560,7 +6560,6 @@ ExpectedDecl 
ASTNodeImporter::VisitClassTemplateSpecializationDecl(
             ASTTemplateArgumentListInfo::Create(Importer.getToContext(),
                                                 ToTAInfo),
             ClassTemplate, ArrayRef(TemplateArgs),
-            /*CanonInjectedTST=*/CanQualType(),
             cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
       return D2;
 
diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp
index cfd47e82b04b5..82d6f51fbabdb 100644
--- a/clang/lib/AST/AttrImpl.cpp
+++ b/clang/lib/AST/AttrImpl.cpp
@@ -442,7 +442,7 @@ inline void profileAttrArg<Attr *>(llvm::FoldingSetNodeID 
&ID,
 template <>
 inline void profileAttrArg<Expr *>(llvm::FoldingSetNodeID &ID,
                                    const ASTContext &Ctx, Expr *E) {
-  E->Profile(ID, Ctx, /*Canonical=*/true);
+  E->Profile(ID, Ctx, CanonicalizationKind::Functional);
 }
 
 template <>
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index e127a08e8620a..8fe9a7c27cd16 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -1157,15 +1157,13 @@ 
ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
     SourceLocation IdLoc, TemplateParameterList *Params,
     const ASTTemplateArgumentListInfo *ArgsAsWritten,
     ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
-    CanQualType CanonInjectedTST,
     ClassTemplatePartialSpecializationDecl *PrevDecl)
     : ClassTemplateSpecializationDecl(
           Context, ClassTemplatePartialSpecialization, TK, DC, StartLoc, IdLoc,
           // Tracking StrictPackMatch for Partial
           // Specializations is not needed.
           SpecializedTemplate, Args, /*StrictPackMatch=*/false, PrevDecl),
-      InstantiatedFromMember(nullptr, false),
-      CanonInjectedTST(CanonInjectedTST) {
+      InstantiatedFromMember(nullptr, false) {
   setSpecializationKind(TSK_ExplicitSpecialization);
   setExplicitSpecializationInfo(Params, ArgsAsWritten);
 }
@@ -1176,12 +1174,11 @@ ClassTemplatePartialSpecializationDecl::Create(
     SourceLocation IdLoc, TemplateParameterList *Params,
     const ASTTemplateArgumentListInfo *ArgsAsWritten,
     ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
-    CanQualType CanonInjectedTST,
     ClassTemplatePartialSpecializationDecl *PrevDecl) {
   assert(!Params->empty() && "template with no template parameters");
   return new (Context, DC) ClassTemplatePartialSpecializationDecl(
       Context, TK, DC, StartLoc, IdLoc, Params, ArgsAsWritten,
-      SpecializedTemplate, Args, CanonInjectedTST, PrevDecl);
+      SpecializedTemplate, Args, PrevDecl);
 }
 
 ClassTemplatePartialSpecializationDecl *
@@ -1194,11 +1191,13 @@ CanQualType
 ClassTemplatePartialSpecializationDecl::getCanonicalInjectedSpecializationType(
     const ASTContext &Ctx) const {
   if (CanonInjectedTST.isNull()) {
+    SmallVector<TemplateArgument, 4> 
CanonicalArgs(getTemplateArgs().asArray());
+    Ctx.canonicalizeTemplateArguments(CanonicalArgs);
     CanonInjectedTST =
         CanQualType::CreateUnsafe(Ctx.getCanonicalTemplateSpecializationType(
             ElaboratedTypeKeyword::None,
             TemplateName(getSpecializedTemplate()->getCanonicalDecl()),
-            getTemplateArgs().asArray()));
+            CanonicalArgs));
   }
   return CanonInjectedTST;
 }
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index ffb3d74f6b9f4..e7f8da368c26b 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -1791,8 +1791,16 @@ void 
JSONNodeDumper::VisitTemplateExpansionTemplateArgument(
 void JSONNodeDumper::VisitExpressionTemplateArgument(
     const TemplateArgument &TA) {
   JOS.attribute("isExpr", true);
-  if (TA.isCanonicalExpr())
-    JOS.attribute("isCanonical", true);
+  if (auto Kind = TA.getExprCanonKind()) {
+    switch (*Kind) {
+    case CanonicalizationKind::Structural:
+      JOS.attribute("CanonicalKind", "Structural");
+      break;
+    case CanonicalizationKind::Functional:
+      JOS.attribute("CanonicalKind", "Functional");
+      break;
+    }
+  }
 }
 void JSONNodeDumper::VisitPackTemplateArgument(const TemplateArgument &TA) {
   JOS.attribute("isPack", true);
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 1f20e2aee0619..1eab0fc3c2cd1 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -1000,10 +1000,6 @@ class ODRTypeVisitor : public 
TypeVisitor<ODRTypeVisitor> {
     VisitType(T);
   }
 
-  void VisitDependentDecltypeType(const DependentDecltypeType *T) {
-    VisitDecltypeType(T);
-  }
-
   void VisitDeducedType(const DeducedType *T) {
     AddQualType(T->getDeducedType());
     VisitType(T);
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 371a6bdbbefa6..1341a71dffc0e 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -1428,10 +1428,10 @@ void StmtProfiler::VisitConstantExpr(const ConstantExpr 
*S) {
 
 void StmtProfiler::VisitDeclRefExpr(const DeclRefExpr *S) {
   VisitExpr(S);
-  if (!Canonical)
+  if (!CanonKind)
     VisitNestedNameSpecifier(S->getQualifier());
   VisitDecl(S->getDecl());
-  if (!Canonical) {
+  if (!CanonKind) {
     ID.AddBoolean(S->hasExplicitTemplateArgs());
     if (S->hasExplicitTemplateArgs())
       VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
@@ -1585,7 +1585,7 @@ void StmtProfiler::VisitCallExpr(const CallExpr *S) {
 void StmtProfiler::VisitMemberExpr(const MemberExpr *S) {
   VisitExpr(S);
   VisitDecl(S->getMemberDecl());
-  if (!Canonical)
+  if (!CanonKind)
     VisitNestedNameSpecifier(S->getQualifier());
   ID.AddBoolean(S->isArrow());
 }
diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index 0ddf49bb19b5c..100e91f454d84 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -449,7 +449,7 @@ bool TemplateArgument::structurallyEquals(const 
TemplateArgument &Other) const {
     return TypeOrValue.V == Other.TypeOrValue.V;
   case Expression:
     return TypeOrValue.V == Other.TypeOrValue.V &&
-           TypeOrValue.IsCanonicalExpr == Other.TypeOrValue.IsCanonicalExpr;
+           TypeOrValue.ExprCanonKind == Other.TypeOrValue.ExprCanonKind;
 
   case Template:
   case TemplateExpansion:
@@ -495,7 +495,7 @@ TemplateArgument 
TemplateArgument::getPackExpansionPattern() const {
 
   case Expression:
     return TemplateArgument(cast<PackExpansionExpr>(getAsExpr())->getPattern(),
-                            isCanonicalExpr());
+                            getExprCanonKind());
 
   case TemplateExpansion:
     return TemplateArgument(getAsTemplateOrTemplatePattern());
@@ -568,7 +568,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy, 
raw_ostream &Out,
 
   case Expression: {
     PrintingPolicy ExprPolicy = Policy;
-    ExprPolicy.PrintAsCanonical = isCanonicalExpr();
+    ExprPolicy.PrintAsCanonical = bool(getExprCanonKind());
     getAsExpr()->printPretty(Out, nullptr, ExprPolicy);
     break;
   }
diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp
index 797a354c5d0fa..a1e90fdc78301 100644
--- a/clang/lib/AST/TemplateName.cpp
+++ b/clang/lib/AST/TemplateName.cpp
@@ -361,12 +361,7 @@ TemplateNameDependence TemplateName::getDependence() const 
{
       if (TTP->isParameterPack())
         D |= TemplateNameDependence::UnexpandedPack;
     }
-    // FIXME: Hack, getDeclContext() can be null if Template is still
-    // initializing due to PCH reading, so we check it before using it.
-    // Should probably modify TemplateSpecializationType to allow constructing
-    // it without the isDependent() checking.
-    if (Template->getDeclContext() &&
-        Template->getDeclContext()->isDependentContext())
+    if (Template->getDeclContext()->isDependentContext())
       D |= TemplateNameDependence::DependentInstantiation;
     return D;
   }
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index d90090b82fb7a..6d5ac8b1a8aeb 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1399,8 +1399,16 @@ void 
TextNodeDumper::VisitTemplateExpansionTemplateArgument(
 void TextNodeDumper::VisitExpressionTemplateArgument(
     const TemplateArgument &TA) {
   OS << " expr";
-  if (TA.isCanonicalExpr())
-    OS << " canonical";
+  if (auto Kind = TA.getExprCanonKind()) {
+    switch (*Kind) {
+    case CanonicalizationKind::Structural:
+      OS << " canonical";
+      break;
+    case CanonicalizationKind::Functional:
+      OS << " canonical-functional";
+      break;
+    }
+  }
   dumpTemplateArgument(TA);
 }
 
@@ -2180,6 +2188,19 @@ void TextNodeDumper::VisitFunctionProtoType(const 
FunctionProtoType *T) {
   VisitFunctionType(T);
 }
 
+void TextNodeDumper::VisitDecltypeType(const DecltypeType *T) {
+  if (auto K = T->getExprCanonicalizationKind()) {
+    switch (*K) {
+    case CanonicalizationKind::Structural:
+      OS << " structural-expr";
+      break;
+    case CanonicalizationKind::Functional:
+      OS << " functional-expr";
+      break;
+    }
+  }
+}
+
 void TextNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
   if (ElaboratedTypeKeyword K = T->getKeyword();
       K != ElaboratedTypeKeyword::None)
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index d501681f0342c..34ed7797a3ba3 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -310,7 +310,7 @@ void ConstantArrayType::Profile(llvm::FoldingSetNodeID &ID,
   ID.AddInteger(TypeQuals);
   ID.AddBoolean(SizeExpr != nullptr);
   if (SizeExpr)
-    SizeExpr->Profile(ID, Context, true);
+    SizeExpr->Profile(ID, Context, CanonicalizationKind::Structural);
 }
 
 QualType ArrayParameterType::getConstantArrayType(const ASTContext &Ctx) const 
{
@@ -332,7 +332,7 @@ void 
DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID,
   ID.AddInteger(llvm::to_underlying(SizeMod));
   ID.AddInteger(TypeQuals);
   if (E)
-    E->Profile(ID, Context, true);
+    E->Profile(ID, Context, CanonicalizationKind::Structural);
 }
 
 DependentVectorType::DependentVectorType(QualType ElementType,
@@ -353,7 +353,7 @@ void DependentVectorType::Profile(llvm::FoldingSetNodeID 
&ID,
                                   VectorKind VecKind) {
   ID.AddPointer(ElementType.getAsOpaquePtr());
   ID.AddInteger(llvm::to_underlying(VecKind));
-  SizeExpr->Profile(ID, Context, true);
+  SizeExpr->Profile(ID, Context, CanonicalizationKind::Structural);
 }
 
 DependentSizedExtVectorType::DependentSizedExtVectorType(QualType ElementType,
@@ -372,7 +372,7 @@ void 
DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID,
                                           QualType ElementType,
                                           Expr *SizeExpr) {
   ID.AddPointer(ElementType.getAsOpaquePtr());
-  SizeExpr->Profile(ID, Context, true);
+  SizeExpr->Profile(ID, Context, CanonicalizationKind::Structural);
 }
 
 DependentAddressSpaceType::DependentAddressSpaceType(QualType PointeeType,
@@ -391,7 +391,7 @@ void 
DependentAddressSpaceType::Profile(llvm::FoldingSetNodeID &ID,
                                         QualType PointeeType,
                                         Expr *AddrSpaceExpr) {
   ID.AddPointer(PointeeType.getAsOpaquePtr());
-  AddrSpaceExpr->Profile(ID, Context, true);
+  AddrSpaceExpr->Profile(ID, Context, CanonicalizationKind::Structural);
 }
 
 MatrixType::MatrixType(TypeClass tc, QualType matrixType, QualType canonType,
@@ -437,8 +437,8 @@ void 
DependentSizedMatrixType::Profile(llvm::FoldingSetNodeID &ID,
                                        QualType ElementType, Expr *RowExpr,
                                        Expr *ColumnExpr) {
   ID.AddPointer(ElementType.getAsOpaquePtr());
-  RowExpr->Profile(ID, CTX, true);
-  ColumnExpr->Profile(ID, CTX, true);
+  RowExpr->Profile(ID, CTX, CanonicalizationKind::Structural);
+  ColumnExpr->Profile(ID, CTX, CanonicalizationKind::Structural);
 }
 
 VectorType::VectorType(QualType vecType, unsigned nElements, QualType 
canonType,
@@ -486,7 +486,7 @@ void DependentBitIntType::Profile(llvm::FoldingSetNodeID 
&ID,
                                   const ASTContext &Context, bool IsUnsigned,
                                   Expr *NumBitsExpr) {
   ID.AddBoolean(IsUnsigned);
-  NumBitsExpr->Profile(ID, Context, true);
+  NumBitsExpr->Profile(ID, Context, CanonicalizationKind::Structural);
 }
 
 bool BoundsAttributedType::referencesFieldDecls() const {
@@ -4063,7 +4063,10 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID 
&ID, QualType Result,
     for (QualType Ex : epi.ExceptionSpec.Exceptions)
       ID.AddPointer(Ex.getAsOpaquePtr());
   } else if (isComputedNoexcept(epi.ExceptionSpec.Type)) {
-    epi.ExceptionSpec.NoexceptExpr->Profile(ID, Context, Canonical);
+    epi.ExceptionSpec.NoexceptExpr->Profile(
+        ID, Context,
+        Canonical ? 
CanonicalizationKindOrNone(CanonicalizationKind::Structural)
+                  : std::nullopt);
   } else if (epi.ExceptionSpec.Type == EST_Uninstantiated ||
              epi.ExceptionSpec.Type == EST_Unevaluated) {
     ID.AddPointer(epi.ExceptionSpec.SourceDecl->getCanonicalDecl());
@@ -4252,7 +4255,7 @@ QualType TypeOfExprType::desugar() const {
 void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
                                       const ASTContext &Context, Expr *E,
                                       bool IsUnqual) {
-  E->Profile(ID, Context, true);
+  E->Profile(ID, Context, CanonicalizationKind::Structural);
   ID.AddBoolean(IsUnqual);
 }
 
@@ -4361,7 +4364,7 @@ void PackIndexingType::Profile(llvm::FoldingSetNodeID &ID,
                                Expr *E, bool FullySubstituted,
                                ArrayRef<QualType> Expansions) {
 
-  E->Profile(ID, Context, true);
+  E->Profile(ID, Context, CanonicalizationKind::Structural);
   ID.AddBoolean(FullySubstituted);
   if (!Expansions.empty()) {
     ID.AddInteger(Expansions.size());
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index e8fbffb9f954d..7a11b044ebf9c 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1364,7 +1364,8 @@ void TypePrinter::printDecltypeBefore(const DecltypeType 
*T, raw_ostream &OS) {
   OS << "decltype(";
   if (const Expr *E = T->getUnderlyingExpr()) {
     PrintingPolicy ExprPolicy = Policy;
-    ExprPolicy.PrintAsCanonical = T->isCanonicalUnqualified();
+    // FIXME: Support printing as functionally equivalent canonical type.
+    ExprPolicy.PrintAsCanonical = bool(T->getExprCanonicalizationKind());
     E->printPretty(OS, nullptr, ExprPolicy);
   }
   OS << ')';
diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp 
b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
index 12442040b13bb..8c576008d263e 100644
--- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -883,7 +883,8 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) {
                                         ICIS_NoInit);
       MemberExpr *ME = MemberExpr::CreateImplicit(
           *Context, PE, true, FD, FD->getType(), VK_LValue, OK_Ordinary);
-      IvarT = Context->getDecltypeType(ME, ME->getType());
+      IvarT = Context->getDecltypeType(ME, /*ExprCanonKind=*/std::nullopt,
+                                       ME->getType());
     }
   }
   convertObjCTypeToCStyleType(IvarT);
@@ -7484,7 +7485,8 @@ Stmt 
*RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) {
                                             /*Mutable=*/true, ICIS_NoInit);
           MemberExpr *ME = MemberExpr::CreateImplicit(
               *Context, PE, true, FD, FD->getType(), VK_LValue, OK_Ordinary);
-          IvarT = Context->getDecltypeType(ME, ME->getType());
+          IvarT = Context->getDecltypeType(ME, /*ExprCanonKind=*/std::nullopt,
+                                           ME->getType());
         }
       }
       convertObjCTypeToCStyleType(IvarT);
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp 
b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index cd0040b3c9fa6..49c0679c28bae 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -855,6 +855,7 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec 
&SS,
 
   TypeLocBuilder TLB;
   DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
+  DecltypeTL.setUnderlyingExpr(DS.getRepAsExpr());
   DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
   DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd());
   SS.Make(Context, TLB.getTypeLocInContext(Context, T), ColonColonLoc);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index d52c12670a57b..6d8bc19509fe0 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11120,10 +11120,10 @@ bool Sema::CheckSizeofMemaccessArgument(const Expr 
*LenExpr, const Expr *Dest,
   QualType PointeeTy = DestPtrTy->getPointeeType();
 
   if (SizeOfArgID == llvm::FoldingSetNodeID())
-    SizeOfArg->Profile(SizeOfArgID, Context, true);
+    SizeOfArg->Profile(SizeOfArgID, Context, CanonicalizationKind::Structural);
 
   llvm::FoldingSetNodeID DestID;
-  Dest->Profile(DestID, Context, true);
+  Dest->Profile(DestID, Context, CanonicalizationKind::Structural);
   if (DestID == SizeOfArgID) {
     // TODO: For strncpy() and friends, this could suggest sizeof(dst)
     //       over sizeof(src) as well.
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 0d2b5c44f6db9..0e1040d126066 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -182,7 +182,7 @@ struct SatisfactionStackRAII {
 static bool DiagRecursiveConstraintEval(
     Sema &S, llvm::FoldingSetNodeID &ID, const NamedDecl *Templ, const Expr *E,
     const MultiLevelTemplateArgumentList *MLTAL = nullptr) {
-  E->Profile(ID, S.Context, /*Canonical=*/true);
+  E->Profile(ID, S.Context, CanonicalizationKind::Functional);
   if (MLTAL) {
     for (const auto &List : *MLTAL)
       for (const auto &TemplateArg : List.Args)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 274973c78da81..30a58e0ceac2e 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2356,7 +2356,7 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, 
Scope *UDLScope) {
 
   case LOLR_Template: {
     TemplateArgumentListInfo ExplicitArgs;
-    TemplateArgument Arg(Lit, /*IsCanonical=*/false);
+    TemplateArgument Arg(Lit, /*CanonKind=*/std::nullopt);
     TemplateArgumentLocInfo ArgInfo(Lit);
     ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo));
     return BuildLiteralOperatorCall(R, OpNameInfo, {}, StringTokLocs.back(),
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index b6099b37104f8..2af98bdcd523f 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -7427,6 +7427,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr 
*Base,
   case DeclSpec::TST_decltype: {
     T = BuildDecltypeType(DS.getRepAsExpr(), /*AsUnevaluated=*/false);
     DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
+    DecltypeTL.setUnderlyingExpr(DS.getRepAsExpr());
     DecltypeTL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
     DecltypeTL.setRParenLoc(DS.getTypeofParensRange().getEnd());
     break;
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 65b60964d1192..1292680f9cd22 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -3754,7 +3754,8 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
           SFINAETrap Trap(*this);
           CheckTemplateArgumentInfo CTAI;
           TemplateArgumentLoc Arg(
-              TemplateArgument(StringLit, /*IsCanonical=*/false), StringLit);
+              TemplateArgument(StringLit, /*CanonKind=*/std::nullopt),
+              StringLit);
           if (CheckTemplateArgument(
                   Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
                   /*ArgumentPackIndex=*/0, CTAI, CTAK_Specified) ||
diff --git a/clang/lib/Sema/SemaOpenACCAtomic.cpp 
b/clang/lib/Sema/SemaOpenACCAtomic.cpp
index dbe7e9739c2f9..f381b96d1678d 100644
--- a/clang/lib/Sema/SemaOpenACCAtomic.cpp
+++ b/clang/lib/Sema/SemaOpenACCAtomic.cpp
@@ -424,9 +424,9 @@ class AtomicOperandChecker {
 
     llvm::FoldingSetNodeID LHS_ID, InnerLHS_ID, InnerRHS_ID;
     AssignInf.LHS->Profile(LHS_ID, SemaRef.getASTContext(),
-                           /*Canonical=*/true);
+                           CanonicalizationKind::Structural);
     BinInf->LHS->Profile(InnerLHS_ID, SemaRef.getASTContext(),
-                         /*Canonical=*/true);
+                         CanonicalizationKind::Structural);
 
     // This is X = X binop expr;
     // Check the RHS is an expression.
@@ -440,7 +440,7 @@ class AtomicOperandChecker {
           IDACInfo::AssignBinOp, AssignInf.LHS};
 
     BinInf->RHS->Profile(InnerRHS_ID, SemaRef.getASTContext(),
-                         /*Canonical=*/true);
+                         CanonicalizationKind::Structural);
     // This is X = expr binop X;
     // Check the LHS is an expression
     if (LHS_ID == InnerRHS_ID)
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 61da3398137d0..29a26e7918780 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3513,13 +3513,14 @@ getAllocatorKind(Sema &S, DSAStackTy *Stack, Expr 
*Allocator) {
   auto AllocatorKindRes = OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
   llvm::FoldingSetNodeID AEId;
   const Expr *AE = Allocator->IgnoreParenImpCasts();
-  AE->IgnoreImpCasts()->Profile(AEId, S.getASTContext(), /*Canonical=*/true);
+  AE->IgnoreImpCasts()->Profile(AEId, S.getASTContext(),
+                                CanonicalizationKind::Structural);
   for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
     auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
     const Expr *DefAllocator = Stack->getAllocator(AllocatorKind);
     llvm::FoldingSetNodeID DAEId;
     DefAllocator->IgnoreImpCasts()->Profile(DAEId, S.getASTContext(),
-                                            /*Canonical=*/true);
+                                            CanonicalizationKind::Structural);
     if (AEId == DAEId) {
       AllocatorKindRes = AllocatorKind;
       break;
@@ -11835,11 +11836,11 @@ bool OpenMPAtomicUpdateChecker::checkBinaryOperation(
         Expr *RHS = AtomicInnerBinOp->getRHS();
         llvm::FoldingSetNodeID XId, LHSId, RHSId;
         X->IgnoreParenImpCasts()->Profile(XId, SemaRef.getASTContext(),
-                                          /*Canonical=*/true);
+                                          CanonicalizationKind::Structural);
         LHS->IgnoreParenImpCasts()->Profile(LHSId, SemaRef.getASTContext(),
-                                            /*Canonical=*/true);
+                                            CanonicalizationKind::Structural);
         RHS->IgnoreParenImpCasts()->Profile(RHSId, SemaRef.getASTContext(),
-                                            /*Canonical=*/true);
+                                            CanonicalizationKind::Structural);
         if (XId == LHSId) {
           E = RHS;
           IsXLHSInRHSPart = true;
@@ -11981,7 +11982,8 @@ bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, 
unsigned DiagId,
 /// Get the node id of the fixed point of an expression \a S.
 llvm::FoldingSetNodeID getNodeId(ASTContext &Context, const Expr *S) {
   llvm::FoldingSetNodeID Id;
-  S->IgnoreParenImpCasts()->Profile(Id, Context, true);
+  S->IgnoreParenImpCasts()->Profile(Id, Context,
+                                    CanonicalizationKind::Structural);
   return Id;
 }
 
@@ -13208,8 +13210,10 @@ StmtResult 
SemaOpenMP::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
             // Check that the first expression has form v = x.
             Expr *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts();
             llvm::FoldingSetNodeID XId, PossibleXId;
-            Checker.getX()->Profile(XId, Context, /*Canonical=*/true);
-            PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true);
+            Checker.getX()->Profile(XId, Context,
+                                    CanonicalizationKind::Structural);
+            PossibleX->Profile(PossibleXId, Context,
+                               CanonicalizationKind::Structural);
             IsUpdateExprFound = XId == PossibleXId;
             if (IsUpdateExprFound) {
               V = BinOp->getLHS();
@@ -13239,8 +13243,10 @@ StmtResult 
SemaOpenMP::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
               // Check that the second expression has form v = x.
               Expr *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts();
               llvm::FoldingSetNodeID XId, PossibleXId;
-              Checker.getX()->Profile(XId, Context, /*Canonical=*/true);
-              PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true);
+              Checker.getX()->Profile(XId, Context,
+                                      CanonicalizationKind::Structural);
+              PossibleX->Profile(PossibleXId, Context,
+                                 CanonicalizationKind::Structural);
               IsUpdateExprFound = XId == PossibleXId;
               if (IsUpdateExprFound) {
                 V = BinOp->getLHS();
@@ -13283,10 +13289,10 @@ StmtResult 
SemaOpenMP::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
                   Expr *PossibleXLHSInSecond =
                       SecondBinOp->getLHS()->IgnoreParenImpCasts();
                   llvm::FoldingSetNodeID X1Id, X2Id;
-                  PossibleXRHSInFirst->Profile(X1Id, Context,
-                                               /*Canonical=*/true);
-                  PossibleXLHSInSecond->Profile(X2Id, Context,
-                                                /*Canonical=*/true);
+                  PossibleXRHSInFirst->Profile(
+                      X1Id, Context, CanonicalizationKind::Structural);
+                  PossibleXLHSInSecond->Profile(
+                      X2Id, Context, CanonicalizationKind::Structural);
                   IsUpdateExprFound = X1Id == X2Id;
                   if (IsUpdateExprFound) {
                     V = FirstBinOp->getLHS();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 0365183ee1b09..1d63ba76c0d46 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -950,7 +950,8 @@ static TemplateArgumentLoc translateTemplateArgument(Sema 
&SemaRef,
 
   case ParsedTemplateArgument::NonType: {
     Expr *E = Arg.getAsExpr();
-    return TemplateArgumentLoc(TemplateArgument(E, /*IsCanonical=*/false), E);
+    return TemplateArgumentLoc(TemplateArgument(E, /*CanonKind=*/std::nullopt),
+                               E);
   }
 
   case ParsedTemplateArgument::Template: {
@@ -1647,7 +1648,7 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, 
Declarator &D,
 
     Param->setDefaultArgument(
         Context, getTrivialTemplateArgumentLoc(
-                     TemplateArgument(Default, /*IsCanonical=*/false),
+                     TemplateArgument(Default, /*CanonKind=*/std::nullopt),
                      QualType(), SourceLocation()));
   }
 
@@ -5644,7 +5645,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, 
TemplateArgumentLoc &ArgLoc,
       // If the resulting expression is new, then use it in place of the
       // old expression in the template argument.
       if (R != E) {
-        TemplateArgument TA(R, /*IsCanonical=*/false);
+        TemplateArgument TA(R, /*CanonKind=*/std::nullopt);
         ArgLoc = TemplateArgumentLoc(TA, R);
       }
       break;
@@ -6893,7 +6894,7 @@ static bool 
CheckTemplateArgumentAddressOfObjectOrFunction(
   // Stop checking the precise nature of the argument if it is value dependent,
   // it should be checked when instantiated.
   if (Arg->isValueDependent()) {
-    SugaredConverted = TemplateArgument(ArgIn, /*IsCanonical=*/false);
+    SugaredConverted = TemplateArgument(ArgIn, /*CanonKind=*/std::nullopt);
     CanonicalConverted =
         S.Context.getCanonicalTemplateArgument(SugaredConverted);
     return false;
@@ -7082,7 +7083,7 @@ static bool CheckTemplateArgumentPointerToMember(
     if (VD->getType()->isMemberPointerType()) {
       if (isa<NonTypeTemplateParmDecl>(VD)) {
         if (Arg->isTypeDependent() || Arg->isValueDependent()) {
-          SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
+          SugaredConverted = TemplateArgument(Arg, /*CanonKind=*/std::nullopt);
           CanonicalConverted =
               S.Context.getCanonicalTemplateArgument(SugaredConverted);
         } else {
@@ -7148,7 +7149,7 @@ static bool CheckTemplateArgumentPointerToMember(
     // Okay: this is the address of a non-static member, and therefore
     // a member pointer constant.
     if (Arg->isTypeDependent() || Arg->isValueDependent()) {
-      SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
+      SugaredConverted = TemplateArgument(Arg, /*CanonKind=*/std::nullopt);
       CanonicalConverted =
           S.Context.getCanonicalTemplateArgument(SugaredConverted);
     } else {
@@ -7273,7 +7274,7 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, 
QualType ParamType,
         return ExprError();
       setDeductionArg(E.get());
     }
-    SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
+    SugaredConverted = TemplateArgument(Arg, /*CanonKind=*/std::nullopt);
     CanonicalConverted = TemplateArgument(
         Context.getCanonicalTemplateArgument(SugaredConverted));
     return Arg;
@@ -7304,7 +7305,7 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, 
QualType ParamType,
   // normal template rules apply: we accept the template if it would be valid
   // for any number of expansions (i.e. none).
   if (ArgPE && !StrictCheck) {
-    SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
+    SugaredConverted = TemplateArgument(Arg, /*CanonKind=*/std::nullopt);
     CanonicalConverted = TemplateArgument(
         Context.getCanonicalTemplateArgument(SugaredConverted));
     return Arg;
@@ -7330,7 +7331,7 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, 
QualType ParamType,
       return Arg;
     }
     if (isa<NonTypeTemplateParmDecl>(ND)) {
-      SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
+      SugaredConverted = TemplateArgument(Arg, /*CanonKind=*/std::nullopt);
       CanonicalConverted =
           Context.getCanonicalTemplateArgument(SugaredConverted);
       return Arg;
@@ -7387,7 +7388,7 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, 
QualType ParamType,
     // permitted (and expected) to be unable to determine a value.
     if (ArgResult.get()->isValueDependent()) {
       setDeductionArg(ArgResult.get());
-      SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
+      SugaredConverted = TemplateArgument(Arg, /*CanonKind=*/std::nullopt);
       CanonicalConverted =
           Context.getCanonicalTemplateArgument(SugaredConverted);
       return Arg;
@@ -7425,7 +7426,7 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, 
QualType ParamType,
           Value.getLValuePath()[0].getAsArrayIndex() == 0 &&
           !Value.isLValueOnePastTheEnd() && ParamType->isPointerType()) {
         if (ArgPE) {
-          SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
+          SugaredConverted = TemplateArgument(Arg, /*CanonKind=*/std::nullopt);
           CanonicalConverted =
               Context.getCanonicalTemplateArgument(SugaredConverted);
         } else {
@@ -7456,7 +7457,7 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, 
QualType ParamType,
       return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff);
 
     if (ArgPE) {
-      SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
+      SugaredConverted = TemplateArgument(Arg, /*CanonKind=*/std::nullopt);
       CanonicalConverted =
           Context.getCanonicalTemplateArgument(SugaredConverted);
     } else {
@@ -7504,7 +7505,7 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, 
QualType ParamType,
 
       // We can't check arbitrary value-dependent arguments.
       if (Arg->isValueDependent()) {
-        SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
+        SugaredConverted = TemplateArgument(Arg, /*CanonKind=*/std::nullopt);
         CanonicalConverted =
             Context.getCanonicalTemplateArgument(SugaredConverted);
         return Arg;
@@ -7593,7 +7594,7 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, 
QualType ParamType,
     if (Arg->isValueDependent()) {
       // The argument is value-dependent. Create a new
       // TemplateArgument with the converted expression.
-      SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
+      SugaredConverted = TemplateArgument(Arg, /*CanonKind=*/std::nullopt);
       CanonicalConverted =
           Context.getCanonicalTemplateArgument(SugaredConverted);
       return Arg;
@@ -7764,7 +7765,7 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, 
QualType ParamType,
   // Deal with parameters of type std::nullptr_t.
   if (ParamType->isNullPtrType()) {
     if (Arg->isTypeDependent() || Arg->isValueDependent()) {
-      SugaredConverted = TemplateArgument(Arg, /*IsCanonical=*/false);
+      SugaredConverted = TemplateArgument(Arg, /*CanonKind=*/std::nullopt);
       CanonicalConverted =
           Context.getCanonicalTemplateArgument(SugaredConverted);
       return Arg;
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp 
b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 1b353d0e0092d..fbf478e91612f 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -546,8 +546,9 @@ DeduceNullPtrTemplateArgument(Sema &S, 
TemplateParameterList *TemplateParams,
                                                         : CK_NullToPointer)
                     .get();
   return DeduceNonTypeTemplateArgument(
-      S, TemplateParams, NTTP, TemplateArgument(Value, /*IsCanonical=*/false),
-      Value->getType(), Info, PartialOrdering, Deduced, HasDeducedAnyParam);
+      S, TemplateParams, NTTP,
+      TemplateArgument(Value, /*CanonKind=*/std::nullopt), Value->getType(),
+      Info, PartialOrdering, Deduced, HasDeducedAnyParam);
 }
 
 /// Deduce the value of the given non-type template parameter
@@ -561,8 +562,9 @@ DeduceNonTypeTemplateArgument(Sema &S, 
TemplateParameterList *TemplateParams,
                               SmallVectorImpl<DeducedTemplateArgument> 
&Deduced,
                               bool *HasDeducedAnyParam) {
   return DeduceNonTypeTemplateArgument(
-      S, TemplateParams, NTTP, TemplateArgument(Value, /*IsCanonical=*/false),
-      Value->getType(), Info, PartialOrdering, Deduced, HasDeducedAnyParam);
+      S, TemplateParams, NTTP,
+      TemplateArgument(Value, /*CanonKind=*/std::nullopt), Value->getType(),
+      Info, PartialOrdering, Deduced, HasDeducedAnyParam);
 }
 
 /// Deduce the value of the given non-type template parameter
@@ -2870,7 +2872,8 @@ Sema::getTrivialTemplateArgumentLoc(const 
TemplateArgument &Arg,
       NTTPType = Arg.getParamTypeForDecl();
     Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
                   .getAs<Expr>();
-    return TemplateArgumentLoc(TemplateArgument(E, /*IsCanonical=*/false), E);
+    return TemplateArgumentLoc(TemplateArgument(E, /*CanonKind=*/std::nullopt),
+                               E);
   }
 
   case TemplateArgument::NullPtr: {
@@ -2885,7 +2888,8 @@ Sema::getTrivialTemplateArgumentLoc(const 
TemplateArgument &Arg,
   case TemplateArgument::Integral:
   case TemplateArgument::StructuralValue: {
     Expr *E = BuildExpressionFromNonTypeTemplateArgument(Arg, Loc).get();
-    return TemplateArgumentLoc(TemplateArgument(E, /*IsCanonical=*/false), E);
+    return TemplateArgumentLoc(TemplateArgument(E, /*CanonKind=*/std::nullopt),
+                               E);
   }
 
     case TemplateArgument::Template:
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index d27130438a500..119c962b07d62 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -6082,6 +6082,7 @@ namespace {
     }
     void VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
       assert(DS.getTypeSpecType() == DeclSpec::TST_decltype);
+      TL.setUnderlyingExpr(DS.getRepAsExpr());
       TL.setDecltypeLoc(DS.getTypeSpecTypeLoc());
       TL.setRParenLoc(DS.getTypeofParensRange().getEnd());
     }
@@ -10083,7 +10084,8 @@ QualType Sema::BuildDecltypeType(Expr *E, bool 
AsUnevaluated) {
     // used to build SFINAE gadgets.
     Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context);
   }
-  return Context.getDecltypeType(E, getDecltypeForExpr(E));
+  return Context.getDecltypeType(E, /*ExprCanonKind=*/std::nullopt,
+                                 getDecltypeForExpr(E));
 }
 
 QualType Sema::ActOnPackIndexingType(QualType Pattern, Expr *IndexExpr,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 49e643e04c426..bdf1ab4204ee3 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4077,7 +4077,7 @@ class TreeTransform {
         return TemplateArgumentLoc();
 
       return TemplateArgumentLoc(TemplateArgument(Result.get(),
-                                                  /*IsCanonical=*/false),
+                                                  /*CanonKind=*/std::nullopt),
                                  Result.get());
     }
 
@@ -5108,7 +5108,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument(
     if (E.isInvalid())
       return true;
     Output = TemplateArgumentLoc(
-        TemplateArgument(E.get(), /*IsCanonical=*/false), E.get());
+        TemplateArgument(E.get(), /*CanonKind=*/std::nullopt), E.get());
     return false;
   }
   }
@@ -7056,17 +7056,15 @@ QualType 
TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB,
   return Result;
 }
 
-template<typename Derived>
+template <typename Derived>
 QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
                                                        DecltypeTypeLoc TL) {
-  const DecltypeType *T = TL.getTypePtr();
-
   // decltype expressions are not potentially evaluated contexts
   EnterExpressionEvaluationContext Unevaluated(
       SemaRef, Sema::ExpressionEvaluationContext::Unevaluated, nullptr,
       Sema::ExpressionEvaluationContextRecord::EK_Decltype);
 
-  ExprResult E = getDerived().TransformExpr(T->getUnderlyingExpr());
+  ExprResult E = getDerived().TransformExpr(TL.getUnderlyingExpr());
   if (E.isInvalid())
     return QualType();
 
@@ -16561,7 +16559,7 @@ 
TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
         ArgStorage = TemplateArgument(
             new (getSema().Context)
                 PackExpansionExpr(DRE.get(), E->getPackLoc(), std::nullopt),
-            /*IsCanonical=*/false);
+            /*CanonKind=*/std::nullopt);
       }
       PackArgs = ArgStorage;
     }
@@ -16779,9 +16777,11 @@ ExprResult 
TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr(
     Replacement = E->getReplacement();
   }
 
+  // FIXME: Track in SubstNonTypeTemplateParmExpr the canonical kind of the
+  // expression.
   return getDerived().RebuildSubstNonTypeTemplateParmExpr(
       AssociatedDecl, E->getIndex(), ParamType, E->getNameLoc(),
-      TemplateArgument(Replacement.get(), /*IsCanonical=*/false),
+      TemplateArgument(Replacement.get(), /*CanonKind=*/std::nullopt),
       E->getPackIndex(), E->getFinal());
 }
 
diff --git a/clang/lib/Serialization/ASTReader.cpp 
b/clang/lib/Serialization/ASTReader.cpp
index b01b18fe3e0ec..866dfa592ca4c 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -7635,6 +7635,7 @@ void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
 }
 
 void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+  TL.setUnderlyingExpr(Reader.readExpr());
   TL.setDecltypeLoc(readSourceLocation());
   TL.setRParenLoc(readSourceLocation());
 }
@@ -10272,12 +10273,12 @@ ASTRecordReader::readTemplateParameterList() {
 }
 
 void ASTRecordReader::readTemplateArgumentList(
-                        SmallVectorImpl<TemplateArgument> &TemplArgs,
-                        bool Canonicalize) {
+    SmallVectorImpl<TemplateArgument> &TemplArgs,
+    CanonicalizationKindOrNone CanonKind) {
   unsigned NumTemplateArgs = readInt();
   TemplArgs.reserve(NumTemplateArgs);
   while (NumTemplateArgs--)
-    TemplArgs.push_back(readTemplateArgument(Canonicalize));
+    TemplArgs.push_back(readTemplateArgument(CanonKind));
 }
 
 /// Read a UnresolvedSet structure.
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp 
b/clang/lib/Serialization/ASTReaderDecl.cpp
index 25598683d1d62..ed520b1dd05dd 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -948,7 +948,8 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
 
     // Template arguments.
     SmallVector<TemplateArgument, 8> TemplArgs;
-    Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true);
+    Record.readTemplateArgumentList(TemplArgs,
+                                    CanonicalizationKind::Structural);
 
     const TemplateParameterList *TemplateParams =
         Record.readBool() ? Record.readTemplateParameterList() : nullptr;
@@ -2454,7 +2455,7 @@ void 
ASTDeclReader::VisitImplicitConceptSpecializationDecl(
   VisitDecl(D);
   llvm::SmallVector<TemplateArgument, 4> Args;
   for (unsigned I = 0; I < D->NumTemplateArgs; ++I)
-    Args.push_back(Record.readTemplateArgument(/*Canonicalize=*/false));
+    Args.push_back(Record.readTemplateArgument());
   D->setTemplateArguments(Args);
 }
 
@@ -2557,7 +2558,7 @@ RedeclarableResult 
ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
   }
 
   SmallVector<TemplateArgument, 8> TemplArgs;
-  Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true);
+  Record.readTemplateArgumentList(TemplArgs, CanonicalizationKind::Functional);
   D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs);
   D->PointOfInstantiation = readSourceLocation();
   D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
@@ -2658,7 +2659,7 @@ RedeclarableResult 
ASTDeclReader::VisitVarTemplateSpecializationDeclImpl(
   }
 
   SmallVector<TemplateArgument, 8> TemplArgs;
-  Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true);
+  Record.readTemplateArgumentList(TemplArgs, CanonicalizationKind::Functional);
   D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs);
   D->PointOfInstantiation = readSourceLocation();
   D->SpecializationKind = (TemplateSpecializationKind)Record.readInt();
diff --git a/clang/lib/Serialization/ASTWriter.cpp 
b/clang/lib/Serialization/ASTWriter.cpp
index ecf935e3b3548..31a6022698ece 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -518,6 +518,7 @@ void TypeLocWriter::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) {
 }
 
 void TypeLocWriter::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) {
+  Record.AddStmt(TL.getUnderlyingExpr());
   addSourceLocation(TL.getDecltypeLoc());
   addSourceLocation(TL.getRParenLoc());
 }

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to