[clang] [Clang] Bugfixes and improved support for `AttributedType`s in lambdas (PR #85325)

via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 26 13:07:59 PDT 2024


https://github.com/Sirraide updated https://github.com/llvm/llvm-project/pull/85325

>From 907210a3ad3d829a8e49a5c976d129f8653801bf Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 18:24:37 +0100
Subject: [PATCH 01/16] [Clang] Add `dump()` method for `Attr`

---
 clang/include/clang/AST/Attr.h | 2 ++
 clang/lib/AST/ASTDumper.cpp    | 8 ++++++++
 2 files changed, 10 insertions(+)

diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index 8e9b7ad8b46826..6400023947863f 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -112,6 +112,8 @@ class Attr : public AttributeCommonInfo {
   // Pretty print this attribute.
   void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
 
+  void dump() const;
+
   static StringRef getDocumentation(attr::Kind);
 };
 
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index 6efc5bb92e28d2..8d8b8621341ef7 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -361,3 +361,11 @@ LLVM_DUMP_METHOD void ConceptReference::dump(raw_ostream &OS) const {
   ASTDumper P(OS, Ctx, Ctx.getDiagnostics().getShowColors());
   P.Visit(this);
 }
+
+//===----------------------------------------------------------------------===//
+// Attr method implementations
+//===----------------------------------------------------------------------===//
+LLVM_DUMP_METHOD void Attr::dump() const {
+  ASTDumper P(llvm::errs(), /*ShowColors=*/false);
+  P.Visit(this);
+}

>From d719a7605c89ed4ea88734b5386b6009931450f6 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 18:25:18 +0100
Subject: [PATCH 02/16] [Clang] Do not instantiate the same (FunctionProto)Type
 twice

---
 clang/lib/Sema/TreeTransform.h | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 2d22692f3ab750..cf781792935f18 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -7231,12 +7231,22 @@ QualType TreeTransform<Derived>::TransformAttributedType(
   // FIXME: dependent operand expressions?
   if (getDerived().AlwaysRebuild() ||
       modifiedType != oldType->getModifiedType()) {
-    TypeLocBuilder AuxiliaryTLB;
-    AuxiliaryTLB.reserve(TL.getFullDataSize());
-    QualType equivalentType =
-        getDerived().TransformType(AuxiliaryTLB, TL.getEquivalentTypeLoc());
-    if (equivalentType.isNull())
-      return QualType();
+    // Do not transform the equivalent type if it is equal to the modified type.
+    //
+    // This is because, 1. it’s the same type, instantiating it again will yield
+    // the same result anyway, and if it doesn't, then that could be a bug in
+    // and of itself, and 2. instantiating the same TypeLoc twice is a really
+    // bad idea if it's a FunctionProtoType, because instantiating the same
+    // ParmVarDecls twice will cause assertion failures.
+    QualType equivalentType = modifiedType;
+    if (TL.getModifiedLoc().getType() != TL.getEquivalentTypeLoc().getType()) {
+      TypeLocBuilder AuxiliaryTLB;
+      AuxiliaryTLB.reserve(TL.getFullDataSize());
+      equivalentType =
+          getDerived().TransformType(AuxiliaryTLB, TL.getEquivalentTypeLoc());
+      if (equivalentType.isNull())
+        return QualType();
+    }
 
     // Check whether we can add nullability; it is only represented as
     // type sugar, and therefore cannot be diagnosed in any other way.

>From a9c753ab46b40bd7da6f27eb11655fe43acb11de Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 21:40:41 +0100
Subject: [PATCH 03/16] [Clang] Refactor instantiation of a lambda's
 FunctionProtoType

---------

Co-authored-by: Yuxuan Chen <ych at meta.com>
---
 clang/include/clang/Sema/Template.h        | 14 +++-
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 13 +++-
 clang/lib/Sema/TreeTransform.h             | 90 +++++++---------------
 3 files changed, 49 insertions(+), 68 deletions(-)

diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index ce44aca797b0fb..8c379f51ca3d5d 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -411,6 +411,11 @@ enum class TemplateSubstitutionKind : char {
     /// lookup will search our outer scope.
     bool CombineWithOuterScope;
 
+    /// Whether this scope is being used to instantiate a lambda expression,
+    /// in which case it should be reused for instantiating the lambda's
+    /// FunctionProtoType.
+    bool InstantiatingLambda = false;
+
     /// If non-NULL, the template parameter pack that has been
     /// partially substituted per C++0x [temp.arg.explicit]p9.
     NamedDecl *PartiallySubstitutedPack = nullptr;
@@ -425,9 +430,11 @@ enum class TemplateSubstitutionKind : char {
     unsigned NumArgsInPartiallySubstitutedPack;
 
   public:
-    LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
+    LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false,
+                            bool InstantiatingLambda = false)
         : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
-          CombineWithOuterScope(CombineWithOuterScope) {
+          CombineWithOuterScope(CombineWithOuterScope),
+          InstantiatingLambda(InstantiatingLambda) {
       SemaRef.CurrentInstantiationScope = this;
     }
 
@@ -553,6 +560,9 @@ enum class TemplateSubstitutionKind : char {
 
     /// Determine whether D is a pack expansion created in this scope.
     bool isLocalPackExpansion(const Decl *D);
+
+    /// Determine whether this scope is for instantiating a lambda.
+    bool isLambda() const { return InstantiatingLambda; }
   };
 
   class TemplateDeclInstantiator
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 1a0c88703aca01..6c753c9956bddb 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1535,7 +1535,8 @@ namespace {
                                            bool SuppressObjCLifetime);
 
     ExprResult TransformLambdaExpr(LambdaExpr *E) {
-      LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+      LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true,
+                                    /*InstantiatingLambda=*/true);
       Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this);
 
       ExprResult Result = inherited::TransformLambdaExpr(E);
@@ -2276,8 +2277,14 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
                                  CXXRecordDecl *ThisContext,
                                  Qualifiers ThisTypeQuals,
                                  Fn TransformExceptionSpec) {
-  // We need a local instantiation scope for this function prototype.
-  LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
+  // If this is a lambda, then TemplateInstantiator::TransformLambdaExpr will
+  // have already pushed a scope for this prototype, so don't create a second
+  // one. Otherwise, push a new instantiation scope.
+  LocalInstantiationScope *Current = getSema().CurrentInstantiationScope;
+  std::optional<LocalInstantiationScope> Scope;
+  if (!Current || !Current->isLambda())
+    Scope.emplace(SemaRef, /*CombineWithOuterScope=*/true);
+
   return inherited::TransformFunctionProtoType(
       TLB, TL, ThisContext, ThisTypeQuals, TransformExceptionSpec);
 }
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index cf781792935f18..b129f3db2b7a64 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -675,10 +675,6 @@ class TreeTransform {
                                       Qualifiers ThisTypeQuals,
                                       Fn TransformExceptionSpec);
 
-  template <typename Fn>
-  QualType TransformAttributedType(TypeLocBuilder &TLB, AttributedTypeLoc TL,
-                                   Fn TransformModifiedType);
-
   bool TransformExceptionSpec(SourceLocation Loc,
                               FunctionProtoType::ExceptionSpecInfo &ESI,
                               SmallVectorImpl<QualType> &Exceptions,
@@ -7212,11 +7208,10 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
 }
 
 template <typename Derived>
-template <typename Fn>
 QualType TreeTransform<Derived>::TransformAttributedType(
-    TypeLocBuilder &TLB, AttributedTypeLoc TL, Fn TransformModifiedTypeFn) {
+    TypeLocBuilder &TLB, AttributedTypeLoc TL) {
   const AttributedType *oldType = TL.getTypePtr();
-  QualType modifiedType = TransformModifiedTypeFn(TLB, TL.getModifiedLoc());
+  QualType modifiedType = getDerived().TransformType(TLB, TL.getModifiedLoc());
   if (modifiedType.isNull())
     return QualType();
 
@@ -7270,15 +7265,6 @@ QualType TreeTransform<Derived>::TransformAttributedType(
   return result;
 }
 
-template <typename Derived>
-QualType TreeTransform<Derived>::TransformAttributedType(TypeLocBuilder &TLB,
-                                                         AttributedTypeLoc TL) {
-  return getDerived().TransformAttributedType(
-      TLB, TL, [&](TypeLocBuilder &TLB, TypeLoc ModifiedLoc) -> QualType {
-        return getDerived().TransformType(TLB, ModifiedLoc);
-      });
-}
-
 template <typename Derived>
 QualType TreeTransform<Derived>::TransformBTFTagAttributedType(
     TypeLocBuilder &TLB, BTFTagAttributedTypeLoc TL) {
@@ -13840,62 +13826,40 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
     getSema().AddTemplateParametersToLambdaCallOperator(NewCallOperator, Class,
                                                         TPL);
 
-  // Transform the type of the original lambda's call operator.
-  // The transformation MUST be done in the CurrentInstantiationScope since
-  // it introduces a mapping of the original to the newly created
-  // transformed parameters.
   TypeSourceInfo *NewCallOpTSI = nullptr;
-  {
-    auto OldCallOpTypeLoc =
-        E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
-
-    auto TransformFunctionProtoTypeLoc =
-        [this](TypeLocBuilder &TLB, FunctionProtoTypeLoc FPTL) -> QualType {
-      SmallVector<QualType, 4> ExceptionStorage;
-      return this->TransformFunctionProtoType(
-          TLB, FPTL, nullptr, Qualifiers(),
-          [&](FunctionProtoType::ExceptionSpecInfo &ESI, bool &Changed) {
-            return TransformExceptionSpec(FPTL.getBeginLoc(), ESI,
-                                          ExceptionStorage, Changed);
-          });
-    };
-
-    QualType NewCallOpType;
-    TypeLocBuilder NewCallOpTLBuilder;
-
-    if (auto ATL = OldCallOpTypeLoc.getAs<AttributedTypeLoc>()) {
-      NewCallOpType = this->TransformAttributedType(
-          NewCallOpTLBuilder, ATL,
-          [&](TypeLocBuilder &TLB, TypeLoc TL) -> QualType {
-            return TransformFunctionProtoTypeLoc(
-                TLB, TL.castAs<FunctionProtoTypeLoc>());
-          });
-    } else {
-      auto FPTL = OldCallOpTypeLoc.castAs<FunctionProtoTypeLoc>();
-      NewCallOpType = TransformFunctionProtoTypeLoc(NewCallOpTLBuilder, FPTL);
-    }
+  auto OldCallOpTypeLoc =
+      E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
 
-    if (NewCallOpType.isNull())
-      return ExprError();
-    NewCallOpTSI =
-        NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
-  }
+  QualType NewCallOpType;
+  TypeLocBuilder NewCallOpTLBuilder;
 
-  ArrayRef<ParmVarDecl *> Params;
-  if (auto ATL = NewCallOpTSI->getTypeLoc().getAs<AttributedTypeLoc>()) {
-    Params = ATL.getModifiedLoc().castAs<FunctionProtoTypeLoc>().getParams();
-  } else {
-    auto FPTL = NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
-    Params = FPTL.getParams();
-  }
+  NewCallOpType =
+      getDerived().TransformType(NewCallOpTLBuilder, OldCallOpTypeLoc);
+  if (NewCallOpType.isNull())
+    return ExprError();
+  NewCallOpTSI =
+      NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
+
+  auto ExtractParams = [](TypeLoc TL) {
+    auto Impl = [](auto Self, TypeLoc TL) -> ArrayRef<ParmVarDecl *> {
+      if (auto FPTL = TL.getAs<FunctionProtoTypeLoc>())
+        return FPTL.getParams();
+      if (auto ATL = TL.getAs<AttributedTypeLoc>())
+        return Self(Self, ATL.getModifiedLoc());
+      if (auto MQTL = TL.getAs<MacroQualifiedTypeLoc>())
+        return Self(Self, MQTL.getInnerLoc());
+      llvm_unreachable("Unhandled TypeLoc");
+    };
+    return Impl(Impl, TL);
+  };
 
   getSema().CompleteLambdaCallOperator(
       NewCallOperator, E->getCallOperator()->getLocation(),
       E->getCallOperator()->getInnerLocStart(),
       E->getCallOperator()->getTrailingRequiresClause(), NewCallOpTSI,
       E->getCallOperator()->getConstexprKind(),
-      E->getCallOperator()->getStorageClass(), Params,
-      E->hasExplicitResultType());
+      E->getCallOperator()->getStorageClass(),
+      ExtractParams(NewCallOpTSI->getTypeLoc()), E->hasExplicitResultType());
 
   getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
   getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});

>From 4a0878a48682da48eb7fd906a899c1be45d0510e Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 21:45:20 +0100
Subject: [PATCH 04/16] [Clang] Preserve type sugar in more places

---------

Co-authored-by: Doug Wyatt <dwyatt at apple.com>
---
 clang/include/clang/AST/ASTContext.h          |  5 ++++
 clang/lib/AST/ASTContext.cpp                  | 27 ++++++++++++++++---
 .../test/SemaCXX/lambda-conversion-op-cc.cpp  | 10 +++----
 3 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index ff6b64c7f72d57..46165f4d4fd547 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1295,6 +1295,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
   const FunctionType *adjustFunctionType(const FunctionType *Fn,
                                          FunctionType::ExtInfo EInfo);
 
+  /// Change the result type of a function type, preserving sugar such as
+  /// attributed types.
+  QualType adjustFunctionResultType(QualType FunctionType,
+                                    QualType NewResultType);
+
   /// Adjust the given function result type.
   CanQualType getCanonicalFunctionResultType(QualType ResultType) const;
 
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 5a8fae76a43a4d..16cfae0627d66c 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3140,13 +3140,34 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
   return cast<FunctionType>(Result.getTypePtr());
 }
 
+QualType ASTContext::adjustFunctionResultType(QualType FunctionType,
+                                              QualType ResultType) {
+  // Might be wrapped in a macro qualified type.
+  if (const auto *MQT = dyn_cast<MacroQualifiedType>(FunctionType)) {
+    return getMacroQualifiedType(
+        adjustFunctionResultType(MQT->getUnderlyingType(), ResultType),
+        MQT->getMacroIdentifier());
+  }
+
+  // Might have a calling-convention attribute.
+  if (const auto *AT = dyn_cast<AttributedType>(FunctionType)) {
+    return getAttributedType(
+        AT->getAttrKind(),
+        adjustFunctionResultType(AT->getModifiedType(), ResultType),
+        adjustFunctionResultType(AT->getEquivalentType(), ResultType));
+  }
+
+  // Anything else must be a function type. Rebuild it with the new return value.
+  const auto *FPT = FunctionType->castAs<FunctionProtoType>();
+  return getFunctionType(ResultType, FPT->getParamTypes(),
+                         FPT->getExtProtoInfo());
+}
+
 void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
                                                  QualType ResultType) {
   FD = FD->getMostRecentDecl();
   while (true) {
-    const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
-    FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
-    FD->setType(getFunctionType(ResultType, FPT->getParamTypes(), EPI));
+    FD->setType(adjustFunctionResultType(FD->getType(), ResultType));
     if (FunctionDecl *Next = FD->getPreviousDecl())
       FD = Next;
     else
diff --git a/clang/test/SemaCXX/lambda-conversion-op-cc.cpp b/clang/test/SemaCXX/lambda-conversion-op-cc.cpp
index 16ca5535019dff..1a6d197af302fd 100644
--- a/clang/test/SemaCXX/lambda-conversion-op-cc.cpp
+++ b/clang/test/SemaCXX/lambda-conversion-op-cc.cpp
@@ -44,19 +44,19 @@ void useage() {
 
   // CHECK: VarDecl {{.*}} vectorcall '
   // CHECK: LambdaExpr
-  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int, float, double) __attribute__((vectorcall)) const'
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int, float, double) const __attribute__((vectorcall))':'void (int, float, double) __attribute__((vectorcall)) const'
   // CHECK: CXXConversionDecl {{.*}} operator void (*)(int, float, double) __attribute__((vectorcall)) 'void
   // CHECK: CXXMethodDecl {{.*}} __invoke 'void (int, float, double) __attribute__((vectorcall))' static inline
 
   // WIN32: VarDecl {{.*}} thiscall '
   // WIN32: LambdaExpr
-  // WIN32: CXXMethodDecl {{.*}} operator() 'void (int, float, double) __attribute__((thiscall)) const'
+  // WIN32: CXXMethodDecl {{.*}} operator() 'void (int, float, double) const __attribute__((thiscall))':'void (int, float, double) __attribute__((thiscall)) const'
   // WIN32: CXXConversionDecl {{.*}} operator void (*)(int, float, double) 'void
   // WIN32: CXXMethodDecl {{.*}} __invoke 'void (int, float, double)' static inline
 
   // CHECK: VarDecl {{.*}} cdecl '
   // CHECK: LambdaExpr
-  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int, float, double) const'
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int, float, double) const __attribute__((cdecl))':'void (int, float, double) const'
   // NODEF: CXXConversionDecl {{.*}} operator void (*)(int, float, double) 'void
   // NODEF: CXXMethodDecl {{.*}} __invoke 'void (int, float, double)' static inline
   // VECTDEF: CXXConversionDecl {{.*}} operator void (*)(int, float, double) __attribute__((vectorcall)) 'void
@@ -108,8 +108,8 @@ void useage() {
   // CHECK: LambdaExpr
   // CHECK: FunctionTemplateDecl {{.*}} operator()
   // CHECK: CXXMethodDecl {{.*}} operator() 'auto (auto) __attribute__((vectorcall)) const' inline
-  // CHECK: CXXMethodDecl {{.*}} operator() 'void (char) __attribute__((vectorcall)) const' implicit_instantiation inline
-  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) __attribute__((vectorcall)) const' implicit_instantiation inline
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (char) const __attribute__((vectorcall))':'void (char) __attribute__((vectorcall)) const' implicit_instantiation inline
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((vectorcall))':'void (int) __attribute__((vectorcall)) const' implicit_instantiation inline
   // CHECK: FunctionTemplateDecl {{.*}} operator auto (*)(type-parameter-0-0) __attribute__((vectorcall))
   // LIN64: CXXConversionDecl {{.*}} operator auto (*)(type-parameter-0-0) __attribute__((vectorcall)) 'auto (*() const noexcept)(auto) __attribute__((vectorcall))'
   // LIN64: CXXConversionDecl {{.*}} operator auto (*)(char) __attribute__((vectorcall)) 'void (*() const noexcept)(char) __attribute__((vectorcall))'

>From e5e93bfcaaa077e52499d95a9f2756f1a8bbd223 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 22:26:31 +0100
Subject: [PATCH 05/16] [Clang] Add tests for templated lambdas with attributes

---
 clang/test/SemaCXX/lambda-attributes.cpp | 53 ++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 clang/test/SemaCXX/lambda-attributes.cpp

diff --git a/clang/test/SemaCXX/lambda-attributes.cpp b/clang/test/SemaCXX/lambda-attributes.cpp
new file mode 100644
index 00000000000000..cca334c0446f87
--- /dev/null
+++ b/clang/test/SemaCXX/lambda-attributes.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -ast-dump %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -triple x86_64-pc-linux -include-pch %t -ast-dump-all /dev/null | FileCheck %s
+// expected-no-diagnostics
+
+// Check that we both don't crash on transforming FunctionProtoType's
+// wrapped in type sugar and that we don't drop it when performing
+// instantiations either.
+
+#define PRESERVE __attribute__((preserve_most))
+
+// Skip to the instantiation of f().
+// CHECK: FunctionDecl {{.*}} f 'void ()' implicit_instantiation
+template <typename T>
+void f() {
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((preserve_most))':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
+  (void) [] (T) __attribute__((preserve_most)) { };
+
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation
+  (void) [] (T) [[clang::annotate_type("foo")]] { };
+
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const {{\[}}[clang::annotate_type(...)]] {{\[}}[clang::annotate_type(...)]] {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation
+  (void) [] (T) [[clang::annotate_type("foo")]]
+                [[clang::annotate_type("foo")]]
+                [[clang::annotate_type("foo")]] { };
+
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((preserve_most)) {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
+  (void) [] (T) __attribute__((preserve_most))
+                [[clang::annotate_type("foo")]] { };
+
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((cdecl)) {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation
+  (void) [] (T) __attribute__((cdecl))
+                [[clang::annotate_type("foo")]] { };
+
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation
+  (void) [] (T t) [[clang::annotate_type("foo", t)]] { };
+
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const __attribute__((preserve_most)) {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
+  (void) [] (T t) __attribute__((preserve_most))
+                [[clang::annotate_type("foo", t, t, t, t)]] { };
+
+  // Check that the MacroQualifiedType is preserved.
+  // CHECK: CXXMethodDecl {{.*}} operator() 'PRESERVE void (int) __attribute__((preserve_most)) const':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
+  (void) [] (T) PRESERVE { };
+
+  // CHECK: CXXMethodDecl {{.*}} operator() 'PRESERVE void (int) __attribute__((preserve_most)) const {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
+  (void) [] (T) PRESERVE [[clang::annotate_type("foo")]] { };
+}
+
+void g() {
+  f<int>();
+}
\ No newline at end of file

>From ada50f141d35aceb400971a2be7654623ec0fb5a Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 22:45:44 +0100
Subject: [PATCH 06/16] [Clang] Add test for nested lambda

---
 clang/test/SemaCXX/lambda-attributes.cpp | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/clang/test/SemaCXX/lambda-attributes.cpp b/clang/test/SemaCXX/lambda-attributes.cpp
index cca334c0446f87..a7fbed146b3729 100644
--- a/clang/test/SemaCXX/lambda-attributes.cpp
+++ b/clang/test/SemaCXX/lambda-attributes.cpp
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -fsyntax-only -ast-dump %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-pch -o %t %s
-// RUN: %clang_cc1 -x c++ -triple x86_64-pc-linux -include-pch %t -ast-dump-all /dev/null | FileCheck %s
+// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++23 -fsyntax-only -ast-dump %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++23 -triple x86_64-pc-linux -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++23 -triple x86_64-pc-linux -include-pch %t -ast-dump-all /dev/null | FileCheck %s
 // expected-no-diagnostics
 
 // Check that we both don't crash on transforming FunctionProtoType's
@@ -46,6 +46,15 @@ void f() {
 
   // CHECK: CXXMethodDecl {{.*}} operator() 'PRESERVE void (int) __attribute__((preserve_most)) const {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
   (void) [] (T) PRESERVE [[clang::annotate_type("foo")]] { };
+
+  // CHECK: CXXMethodDecl {{.*}} operator() 'void (int) const {{\[}}[clang::annotate_type(...)]]':'void (int) const' implicit_instantiation
+  (void) [] (T) [[clang::annotate_type("foo")]] {
+    // CHECK: CXXMethodDecl {{.*}} operator() 'PRESERVE void (int) __attribute__((preserve_most)) const {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' implicit_instantiation
+    auto l = []<typename U = T> (U u = {}) PRESERVE [[clang::annotate_type("foo", u)]] { };
+
+    // CHECK: DeclRefExpr {{.*}} 'PRESERVE void (int) __attribute__((preserve_most)) const {{\[}}[clang::annotate_type(...)]]':'void (int) __attribute__((preserve_most)) const' lvalue CXXMethod
+    l();
+  };
 }
 
 void g() {

>From 03135c36495c29c5e10b3f0600e2ff75e07fb6a1 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Thu, 14 Mar 2024 23:17:32 +0100
Subject: [PATCH 07/16] [NFC] clang-format and comment

---
 clang/lib/AST/ASTContext.cpp             |  3 ++-
 clang/lib/Sema/TreeTransform.h           | 10 ++--------
 clang/test/SemaCXX/lambda-attributes.cpp |  2 +-
 3 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 16cfae0627d66c..e9f31047c9caef 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3157,7 +3157,8 @@ QualType ASTContext::adjustFunctionResultType(QualType FunctionType,
         adjustFunctionResultType(AT->getEquivalentType(), ResultType));
   }
 
-  // Anything else must be a function type. Rebuild it with the new return value.
+  // Anything else must be a function type. Rebuild it with the new return
+  // value.
   const auto *FPT = FunctionType->castAs<FunctionProtoType>();
   return getFunctionType(ResultType, FPT->getParamTypes(),
                          FPT->getExtProtoInfo());
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index b129f3db2b7a64..b1a8fd75a90712 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -7208,8 +7208,8 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
 }
 
 template <typename Derived>
-QualType TreeTransform<Derived>::TransformAttributedType(
-    TypeLocBuilder &TLB, AttributedTypeLoc TL) {
+QualType TreeTransform<Derived>::TransformAttributedType(TypeLocBuilder &TLB,
+                                                         AttributedTypeLoc TL) {
   const AttributedType *oldType = TL.getTypePtr();
   QualType modifiedType = getDerived().TransformType(TLB, TL.getModifiedLoc());
   if (modifiedType.isNull())
@@ -7227,12 +7227,6 @@ QualType TreeTransform<Derived>::TransformAttributedType(
   if (getDerived().AlwaysRebuild() ||
       modifiedType != oldType->getModifiedType()) {
     // Do not transform the equivalent type if it is equal to the modified type.
-    //
-    // This is because, 1. it’s the same type, instantiating it again will yield
-    // the same result anyway, and if it doesn't, then that could be a bug in
-    // and of itself, and 2. instantiating the same TypeLoc twice is a really
-    // bad idea if it's a FunctionProtoType, because instantiating the same
-    // ParmVarDecls twice will cause assertion failures.
     QualType equivalentType = modifiedType;
     if (TL.getModifiedLoc().getType() != TL.getEquivalentTypeLoc().getType()) {
       TypeLocBuilder AuxiliaryTLB;
diff --git a/clang/test/SemaCXX/lambda-attributes.cpp b/clang/test/SemaCXX/lambda-attributes.cpp
index a7fbed146b3729..799649719cf42b 100644
--- a/clang/test/SemaCXX/lambda-attributes.cpp
+++ b/clang/test/SemaCXX/lambda-attributes.cpp
@@ -59,4 +59,4 @@ void f() {
 
 void g() {
   f<int>();
-}
\ No newline at end of file
+}

>From dbffae3d49be05965b755152c32ae49250404044 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Fri, 15 Mar 2024 00:31:54 +0100
Subject: [PATCH 08/16] [NFC] Merge declaration and initialisation for some
 local variables

---
 clang/lib/Sema/TreeTransform.h | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index b1a8fd75a90712..ae0cc7b4d8acc3 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13820,18 +13820,14 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
     getSema().AddTemplateParametersToLambdaCallOperator(NewCallOperator, Class,
                                                         TPL);
 
-  TypeSourceInfo *NewCallOpTSI = nullptr;
-  auto OldCallOpTypeLoc =
-      E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
-
-  QualType NewCallOpType;
   TypeLocBuilder NewCallOpTLBuilder;
-
-  NewCallOpType =
+  TypeLoc OldCallOpTypeLoc =
+      E->getCallOperator()->getTypeSourceInfo()->getTypeLoc();
+  QualType NewCallOpType =
       getDerived().TransformType(NewCallOpTLBuilder, OldCallOpTypeLoc);
   if (NewCallOpType.isNull())
     return ExprError();
-  NewCallOpTSI =
+  TypeSourceInfo *NewCallOpTSI =
       NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
 
   auto ExtractParams = [](TypeLoc TL) {

>From d6a57b5a5aa123cf38ce3657b764c74c4c5a86f7 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Fri, 15 Mar 2024 00:55:31 +0100
Subject: [PATCH 09/16] [Clang] Use TypeLoc::getAsAdjusted()

---
 clang/lib/Sema/TreeTransform.h | 18 +++++-------------
 1 file changed, 5 insertions(+), 13 deletions(-)

diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index ae0cc7b4d8acc3..c83e0b009465af 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13830,18 +13830,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
   TypeSourceInfo *NewCallOpTSI =
       NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
 
-  auto ExtractParams = [](TypeLoc TL) {
-    auto Impl = [](auto Self, TypeLoc TL) -> ArrayRef<ParmVarDecl *> {
-      if (auto FPTL = TL.getAs<FunctionProtoTypeLoc>())
-        return FPTL.getParams();
-      if (auto ATL = TL.getAs<AttributedTypeLoc>())
-        return Self(Self, ATL.getModifiedLoc());
-      if (auto MQTL = TL.getAs<MacroQualifiedTypeLoc>())
-        return Self(Self, MQTL.getInnerLoc());
-      llvm_unreachable("Unhandled TypeLoc");
-    };
-    return Impl(Impl, TL);
-  };
+  // The type may be an AttributedType or some other kind of sugar;
+  // get the actual underlying FunctionProtoType.
+  auto FPTL = NewCallOpTSI->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>();
+  assert(FPTL && "Not a FunctionProtoType?");
 
   getSema().CompleteLambdaCallOperator(
       NewCallOperator, E->getCallOperator()->getLocation(),
@@ -13849,7 +13841,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
       E->getCallOperator()->getTrailingRequiresClause(), NewCallOpTSI,
       E->getCallOperator()->getConstexprKind(),
       E->getCallOperator()->getStorageClass(),
-      ExtractParams(NewCallOpTSI->getTypeLoc()), E->hasExplicitResultType());
+      FPTL.getParams(), E->hasExplicitResultType());
 
   getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
   getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});

>From 1fc2027af9726f164dbcdf98372016acd1111336 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Fri, 15 Mar 2024 00:59:10 +0100
Subject: [PATCH 10/16] [NFC] clang-format

---
 clang/lib/Sema/TreeTransform.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index c83e0b009465af..079821c05380e6 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13840,8 +13840,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
       E->getCallOperator()->getInnerLocStart(),
       E->getCallOperator()->getTrailingRequiresClause(), NewCallOpTSI,
       E->getCallOperator()->getConstexprKind(),
-      E->getCallOperator()->getStorageClass(),
-      FPTL.getParams(), E->hasExplicitResultType());
+      E->getCallOperator()->getStorageClass(), FPTL.getParams(),
+      E->hasExplicitResultType());
 
   getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
   getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});

>From 0107caa0ef04f19c819e3b5f92ab75b703ba51c1 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Fri, 15 Mar 2024 02:14:38 +0100
Subject: [PATCH 11/16] [Clang] Add ASTContext::adjustType()

---
 clang/include/clang/AST/ASTContext.h |  10 ++-
 clang/lib/AST/ASTContext.cpp         | 100 +++++++++++++++------------
 2 files changed, 63 insertions(+), 47 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 46165f4d4fd547..70ed07180616e0 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -248,7 +248,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
   mutable llvm::FoldingSet<BitIntType> BitIntTypes;
   mutable llvm::ContextualFoldingSet<DependentBitIntType, ASTContext &>
       DependentBitIntTypes;
-  llvm::FoldingSet<BTFTagAttributedType> BTFTagAttributedTypes;
+  mutable llvm::FoldingSet<BTFTagAttributedType> BTFTagAttributedTypes;
 
   mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
   mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
@@ -1291,6 +1291,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// calling T.withConst().
   QualType getConstType(QualType T) const { return T.withConst(); }
 
+  /// Rebuild a type, preserving any existing type sugar. For function types,
+  /// you probably want to just use \c adjustFunctionResultType and friends
+  /// instead.
+  QualType adjustType(QualType OldType,
+                      llvm::function_ref<QualType(QualType)> Adjust) const;
+
   /// Change the ExtInfo on a function type.
   const FunctionType *adjustFunctionType(const FunctionType *Fn,
                                          FunctionType::ExtInfo EInfo);
@@ -1612,7 +1618,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
                              QualType equivalentType) const;
 
   QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
-                                   QualType Wrapped);
+                                   QualType Wrapped) const;
 
   QualType
   getSubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl,
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index e9f31047c9caef..cd06bbb9b53170 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3122,6 +3122,50 @@ QualType ASTContext::removePtrSizeAddrSpace(QualType T) const {
   return T;
 }
 
+QualType
+ASTContext::adjustType(QualType Orig,
+                       llvm::function_ref<QualType(QualType)> Adjust) const {
+  switch (Orig->getTypeClass()) {
+  case Type::Attributed: {
+    const auto *AT = dyn_cast<AttributedType>(Orig);
+    return getAttributedType(AT->getAttrKind(),
+                             adjustType(AT->getModifiedType(), Adjust),
+                             adjustType(AT->getEquivalentType(), Adjust));
+  }
+
+  case Type::BTFTagAttributed: {
+    const auto *BTFT = dyn_cast<BTFTagAttributedType>(Orig);
+    return getBTFTagAttributedType(BTFT->getAttr(),
+                                   adjustType(BTFT->getWrappedType(), Adjust));
+  }
+
+  case Type::Elaborated: {
+    const auto *ET = cast<ElaboratedType>(Orig);
+    return getElaboratedType(ET->getKeyword(), ET->getQualifier(),
+                             adjustType(ET->getNamedType(), Adjust));
+  }
+
+  case Type::Paren:
+    return getParenType(
+        adjustType(cast<ParenType>(Orig)->getInnerType(), Adjust));
+
+  case Type::Adjusted: {
+    const auto *AT = cast<AdjustedType>(Orig);
+    return getAdjustedType(AT->getOriginalType(),
+                           adjustType(AT->getAdjustedType(), Adjust));
+  }
+
+  case Type::MacroQualified: {
+    const auto *MQT = cast<MacroQualifiedType>(Orig);
+    return getMacroQualifiedType(adjustType(MQT->getUnderlyingType(), Adjust),
+                                 MQT->getMacroIdentifier());
+  }
+
+  default:
+    return Adjust(Orig);
+  }
+}
+
 const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
                                                    FunctionType::ExtInfo Info) {
   if (T->getExtInfo() == Info)
@@ -3142,26 +3186,11 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
 
 QualType ASTContext::adjustFunctionResultType(QualType FunctionType,
                                               QualType ResultType) {
-  // Might be wrapped in a macro qualified type.
-  if (const auto *MQT = dyn_cast<MacroQualifiedType>(FunctionType)) {
-    return getMacroQualifiedType(
-        adjustFunctionResultType(MQT->getUnderlyingType(), ResultType),
-        MQT->getMacroIdentifier());
-  }
-
-  // Might have a calling-convention attribute.
-  if (const auto *AT = dyn_cast<AttributedType>(FunctionType)) {
-    return getAttributedType(
-        AT->getAttrKind(),
-        adjustFunctionResultType(AT->getModifiedType(), ResultType),
-        adjustFunctionResultType(AT->getEquivalentType(), ResultType));
-  }
-
-  // Anything else must be a function type. Rebuild it with the new return
-  // value.
-  const auto *FPT = FunctionType->castAs<FunctionProtoType>();
-  return getFunctionType(ResultType, FPT->getParamTypes(),
-                         FPT->getExtProtoInfo());
+  return adjustType(FunctionType, [&](QualType Orig) {
+    const auto *FPT = Orig->castAs<FunctionProtoType>();
+    return getFunctionType(ResultType, FPT->getParamTypes(),
+                           FPT->getExtProtoInfo());
+  });
 }
 
 void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
@@ -3184,30 +3213,11 @@ void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
 /// and preserved. Other type sugar (for instance, typedefs) is not.
 QualType ASTContext::getFunctionTypeWithExceptionSpec(
     QualType Orig, const FunctionProtoType::ExceptionSpecInfo &ESI) const {
-  // Might have some parens.
-  if (const auto *PT = dyn_cast<ParenType>(Orig))
-    return getParenType(
-        getFunctionTypeWithExceptionSpec(PT->getInnerType(), ESI));
-
-  // Might be wrapped in a macro qualified type.
-  if (const auto *MQT = dyn_cast<MacroQualifiedType>(Orig))
-    return getMacroQualifiedType(
-        getFunctionTypeWithExceptionSpec(MQT->getUnderlyingType(), ESI),
-        MQT->getMacroIdentifier());
-
-  // Might have a calling-convention attribute.
-  if (const auto *AT = dyn_cast<AttributedType>(Orig))
-    return getAttributedType(
-        AT->getAttrKind(),
-        getFunctionTypeWithExceptionSpec(AT->getModifiedType(), ESI),
-        getFunctionTypeWithExceptionSpec(AT->getEquivalentType(), ESI));
-
-  // Anything else must be a function type. Rebuild it with the new exception
-  // specification.
-  const auto *Proto = Orig->castAs<FunctionProtoType>();
-  return getFunctionType(
-      Proto->getReturnType(), Proto->getParamTypes(),
-      Proto->getExtProtoInfo().withExceptionSpec(ESI));
+  return adjustType(Orig, [&](QualType Ty) {
+    const auto *Proto = Ty->castAs<FunctionProtoType>();
+    return getFunctionType(Proto->getReturnType(), Proto->getParamTypes(),
+                           Proto->getExtProtoInfo().withExceptionSpec(ESI));
+  });
 }
 
 bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T,
@@ -4799,7 +4809,7 @@ QualType ASTContext::getAttributedType(attr::Kind attrKind,
 }
 
 QualType ASTContext::getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
-                                             QualType Wrapped) {
+                                             QualType Wrapped) const {
   llvm::FoldingSetNodeID ID;
   BTFTagAttributedType::Profile(ID, Wrapped, BTFAttr);
 

>From c44c182c580a19282f593ab22e6fa4fc7792aa87 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Mon, 26 Aug 2024 21:51:43 +0200
Subject: [PATCH 12/16] Add comment

---
 clang/lib/Sema/SemaTemplateInstantiate.cpp | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 25d50338728020..933377bab2d4ed 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2408,9 +2408,13 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB,
                                  CXXRecordDecl *ThisContext,
                                  Qualifiers ThisTypeQuals,
                                  Fn TransformExceptionSpec) {
-  // If this is a lambda, then TemplateInstantiator::TransformLambdaExpr will
-  // have already pushed a scope for this prototype, so don't create a second
-  // one. Otherwise, push a new instantiation scope.
+  // If this is a lambda, the transformation MUST be done in the
+  // CurrentInstantiationScope since it introduces a mapping of
+  // the original to the newly created transformed parameters.
+  //
+  // In that case, TemplateInstantiator::TransformLambdaExpr will
+  // have already pushed a scope for this prototype, so don't create
+  // a second one.
   LocalInstantiationScope *Current = getSema().CurrentInstantiationScope;
   std::optional<LocalInstantiationScope> Scope;
   if (!Current || !Current->isLambda())

>From 29f06177768514d4be957ea5ded5251df84db097 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Mon, 26 Aug 2024 21:53:49 +0200
Subject: [PATCH 13/16] Handle FunctionNoProtoType

---
 clang/lib/AST/ASTContext.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 345ea656e276e5..151091329dde9b 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3576,6 +3576,9 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
 QualType ASTContext::adjustFunctionResultType(QualType FunctionType,
                                               QualType ResultType) {
   return adjustType(FunctionType, [&](QualType Orig) {
+    if (const auto* FNPT = Orig->getAs<FunctionNoProtoType>())
+      return getFunctionNoProtoType(ResultType, FNPT->getExtInfo());
+
     const auto *FPT = Orig->castAs<FunctionProtoType>();
     return getFunctionType(ResultType, FPT->getParamTypes(),
                            FPT->getExtProtoInfo());

>From b6fef42fe9d8064d7930ccf5d551e0cec6e97e67 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Mon, 26 Aug 2024 22:00:20 +0200
Subject: [PATCH 14/16] Add comment explaining why we don't want to transform
 the same type twice

---
 clang/lib/Sema/TreeTransform.h | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 0fdab111f1291c..75a0388c9af6a6 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -7380,7 +7380,18 @@ QualType TreeTransform<Derived>::TransformAttributedType(TypeLocBuilder &TLB,
   // FIXME: dependent operand expressions?
   if (getDerived().AlwaysRebuild() ||
       modifiedType != oldType->getModifiedType()) {
-    // Do not transform the equivalent type if it is equal to the modified type.
+    // If the equivalent type is equal to the modified type, we don't want to
+    // transform it as well because:
+    //
+    //   1. The transformation would yield the same result and is therefore
+    //      superfluous, and
+    //
+    //   2. Transforming the same type twice can cause problems, e.g. if it
+    //      is a FunctionProtoType, we may end up instantiating the function
+    //      parameters twice, which causes an assertion since the parameters
+    //      are already bound to their counterparts in the template for this
+    //      instantiation.
+    //
     QualType equivalentType = modifiedType;
     if (TL.getModifiedLoc().getType() != TL.getEquivalentTypeLoc().getType()) {
       TypeLocBuilder AuxiliaryTLB;

>From 19a8beb5fe33e07ccc9baf28a280dee547fa9d52 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Mon, 26 Aug 2024 22:01:38 +0200
Subject: [PATCH 15/16] Remove Attr::dump() from this pr

---
 clang/include/clang/AST/Attr.h | 2 --
 clang/lib/AST/ASTDumper.cpp    | 8 --------
 2 files changed, 10 deletions(-)

diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index 028431a923169e..bd1851a26ce2e1 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -112,8 +112,6 @@ class Attr : public AttributeCommonInfo {
   // Pretty print this attribute.
   void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const;
 
-  void dump() const;
-
   static StringRef getDocumentation(attr::Kind);
 };
 
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index 7028ee9576de46..864d0393f9a78e 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -393,11 +393,3 @@ LLVM_DUMP_METHOD void TemplateArgument::dump(llvm::raw_ostream &OS,
   ASTDumper Dumper(OS, Context, Context.getDiagnostics().getShowColors());
   Dumper.Visit(*this);
 }
-
-//===----------------------------------------------------------------------===//
-// Attr method implementations
-//===----------------------------------------------------------------------===//
-LLVM_DUMP_METHOD void Attr::dump() const {
-  ASTDumper P(llvm::errs(), /*ShowColors=*/false);
-  P.Visit(this);
-}

>From bdd35cbf2fdfa05b553c1aa23caf466f802529f2 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Mon, 26 Aug 2024 22:07:41 +0200
Subject: [PATCH 16/16] clang-format

---
 clang/lib/AST/ASTContext.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 151091329dde9b..f9af542e03198f 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3576,7 +3576,7 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
 QualType ASTContext::adjustFunctionResultType(QualType FunctionType,
                                               QualType ResultType) {
   return adjustType(FunctionType, [&](QualType Orig) {
-    if (const auto* FNPT = Orig->getAs<FunctionNoProtoType>())
+    if (const auto *FNPT = Orig->getAs<FunctionNoProtoType>())
       return getFunctionNoProtoType(ResultType, FNPT->getExtInfo());
 
     const auto *FPT = Orig->castAs<FunctionProtoType>();



More information about the cfe-commits mailing list