[clang] Rough first stab at addressing #85120 (PR #85147)

Doug Wyatt via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 13 16:05:56 PDT 2024


https://github.com/dougsonos created https://github.com/llvm/llvm-project/pull/85147

I pointed out this issue in the review for nolock/noalloc, and @Sirraide opened #85120 

Here are some (very rough) bits of code I'd written to try to address the loss of type sugar, plus a subsequent crash involving lambdas (can't remember details now, and the crash may not exist any more on main).

Just in case it helps.

>From 613f04e311f083c129acaa4598cbfd9894fe3805 Mon Sep 17 00:00:00 2001
From: Doug Wyatt <dwyatt at apple.com>
Date: Wed, 13 Mar 2024 16:02:14 -0700
Subject: [PATCH] Rough first stab at addressing #85120

---
 clang/include/clang/AST/ASTContext.h |  5 +++
 clang/lib/AST/ASTContext.cpp         | 62 +++++++++++++++++++++++++++-
 clang/lib/Sema/SemaExpr.cpp          |  2 +-
 clang/lib/Sema/TreeTransform.h       | 61 ++++++++++++++++++++++++++-
 4 files changed, 125 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index ff6b64c7f72d57..ca90417c9bf70b 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1301,6 +1301,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// Change the result type of a function type once it is deduced.
   void adjustDeducedFunctionResultType(FunctionDecl *FD, QualType ResultType);
 
+  /// Transform a function type to have the provided result type, preserving
+  /// AttributedType and MacroQualifiedType sugar.
+  QualType getFunctionTypeWithResultType(QualType OrigFuncType, QualType ResultType,
+    const FunctionProtoType::ExtProtoInfo &EPI) const;
+
   /// Get a function type and produce the equivalent function type with the
   /// specified exception specification. Type sugar that can be present on a
   /// declaration of a function with an exception specification is permitted
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 5a8fae76a43a4d..035dc19ba7011d 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3140,13 +3140,71 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
   return cast<FunctionType>(Result.getTypePtr());
 }
 
+// EPI is provided by the caller because in the case of adjustDeducedFunctionResultType, it
+// is copied entirely from the previous FunctionType, but with a block (ActOnBlockStmtExpr),
+// it is more complicated...
+QualType ASTContext::getFunctionTypeWithResultType(QualType OrigFuncType, QualType ResultType,
+  const FunctionProtoType::ExtProtoInfo &EPI) const
+{
+  // Might be wrapped in a macro qualified type.
+  if (const auto *MQT = dyn_cast<MacroQualifiedType>(OrigFuncType)) {
+    return getMacroQualifiedType(
+        getFunctionTypeWithResultType(MQT->getUnderlyingType(), ResultType, EPI),
+        MQT->getMacroIdentifier());
+  }
+
+  // Might have a calling-convention attribute.
+  if (const auto *AT = dyn_cast<AttributedType>(OrigFuncType)) {
+    return getAttributedType(
+        AT->getAttrKind(),
+        getFunctionTypeWithResultType(AT->getModifiedType(), ResultType, EPI),
+        getFunctionTypeWithResultType(AT->getEquivalentType(), ResultType, EPI));
+  }
+  
+  // Anything else must be a function type. Rebuild it with the new return value.
+  const auto *FPT = OrigFuncType->castAs<FunctionProtoType>();
+  return getFunctionType(ResultType, FPT->getParamTypes(), EPI);
+}
+
+#if 0
+static void examineType(const char* prefix, QualType QT, const char* term)
+{
+  llvm::outs() << prefix;
+  if (const auto *MQT = dyn_cast<MacroQualifiedType>(QT)) {
+    examineType( "MacroQualifiedType <", MQT->getUnderlyingType(), ">");
+  } else if (const auto *AT = dyn_cast<AttributedType>(QT)) {
+    examineType("AttributedType <", AT->getEquivalentType(), ">");
+  } else {
+    const auto *FPT = QT->castAs<FunctionProtoType>();
+    assert(FPT);
+    llvm::outs() << QT;
+  }
+  llvm::outs() << term;
+}
+#endif
+
 void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
                                                  QualType ResultType) {
   FD = FD->getMostRecentDecl();
   while (true) {
-    const auto *FPT = FD->getType()->castAs<FunctionProtoType>();
+    QualType OrigFuncType = FD->getType();
+    const auto *FPT = OrigFuncType->castAs<FunctionProtoType>();
     FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
-    FD->setType(getFunctionType(ResultType, FPT->getParamTypes(), EPI));
+#if 1 // my new way
+    QualType NewFuncType = getFunctionTypeWithResultType(OrigFuncType, ResultType, EPI);
+#else // original way
+    QualType NewFuncType = getFunctionType(ResultType, FPT->getParamTypes(), EPI);
+#endif
+    /*llvm::outs() << "transform " << OrigFuncType << " -> " << NewFuncType << "\n";
+    llvm::outs() << " isConstQualified " << OrigFuncType.isConstQualified() << NewFuncType.isConstQualified() << "\n";
+    llvm::outs() << " isLocalConstQualified " << OrigFuncType.isLocalConstQualified() << NewFuncType.isLocalConstQualified() << "\n";
+    llvm::outs() << " const method " << FPT->isConst() << NewFuncType->castAs<FunctionProtoType>()->isConst() << "\n";
+    llvm::outs() << " canonical " << NewFuncType.getCanonicalType() << "\n";*/
+
+    /*examineType("original ", OrigFuncType, "\n");
+    examineType("deduced ", NewFuncType, "\n");*/
+
+    FD->setType(NewFuncType);
     if (FunctionDecl *Next = FD->getPreviousDecl())
       FD = Next;
     else
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 93f82e68ab6440..651136d7c1b1b8 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -17161,7 +17161,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
       FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
       EPI.TypeQuals = Qualifiers();
       EPI.ExtInfo = Ext;
-      BlockTy = Context.getFunctionType(RetTy, FPT->getParamTypes(), EPI);
+      BlockTy = Context.getFunctionTypeWithResultType(BSI->FunctionType, RetTy, EPI);
     }
 
   // If we don't have a function type, just build one from nothing.
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 2d22692f3ab750..9a8dac2258c1a0 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -13830,6 +13830,33 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
     getSema().AddTemplateParametersToLambdaCallOperator(NewCallOperator, Class,
                                                         TPL);
 
+#if 0
+// Conflicting old bug fix attempt
+
+@@ -13719,10 +13719,23 @@
+   // it introduces a mapping of the original to the newly created
+   // transformed parameters.
+   TypeSourceInfo *NewCallOpTSI = nullptr;
++  // <rdar://117704214> Crash involving AttributedTypeLoc on lambda.
++  // Hack of a fix adapted from https://github.com/llvm/llvm-project/issues/58366
++  FunctionProtoTypeLoc NewCallOpFPTL;
+   {
+     TypeSourceInfo *OldCallOpTSI = E->getCallOperator()->getTypeSourceInfo();
+     auto OldCallOpFPTL =
+         OldCallOpTSI->getTypeLoc().getAs<FunctionProtoTypeLoc>();
++    AttributedTypeLoc OldCallOpATTL;
++    bool IsAttributed = false;
++    if (!OldCallOpFPTL) {
++      OldCallOpATTL = OldCallOpTSI->getTypeLoc().getAs<AttributedTypeLoc>();
++      assert(OldCallOpATTL);
++      OldCallOpFPTL =
++          OldCallOpATTL.getModifiedLoc().getAs<FunctionProtoTypeLoc>();
++      assert(OldCallOpFPTL);
++      IsAttributed = true;
++    }
+#endif
+
+
   // 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
@@ -13867,8 +13894,38 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
 
     if (NewCallOpType.isNull())
       return ExprError();
-    NewCallOpTSI =
-        NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
+
+    // NewCallOpTSI =
+    //     NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, NewCallOpType);
+    if (IsAttributed) {
+      const AttributedType *oldType = OldCallOpATTL.getTypePtr();
+
+      const Attr *newAttr = getDerived().TransformAttr(OldCallOpATTL.getAttr());
+      if (!newAttr)
+        return ExprError();
+
+      QualType equivalentType =
+          getDerived().TransformType(oldType->getEquivalentType());
+      if (equivalentType.isNull())
+        return ExprError();
+      QualType result = SemaRef.Context.getAttributedType(
+          OldCallOpATTL.getAttrKind(), NewCallOpType, equivalentType);
+
+      AttributedTypeLoc newTL =
+          NewCallOpTLBuilder.push<AttributedTypeLoc>(result);
+      newTL.setAttr(newAttr);
+
+      NewCallOpTSI =
+          NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context, result);
+      NewCallOpFPTL = NewCallOpTSI->getTypeLoc()
+                          .castAs<AttributedTypeLoc>()
+                          .getModifiedLoc()
+                          .castAs<FunctionProtoTypeLoc>();
+    } else {
+      NewCallOpTSI = NewCallOpTLBuilder.getTypeSourceInfo(getSema().Context,
+                                                          NewCallOpType);
+      NewCallOpFPTL = NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
+    }
   }
 
   ArrayRef<ParmVarDecl *> Params;



More information about the cfe-commits mailing list