[clang] [clang-tools-extra] FunctionDecl::getFunctionTypeLoc: ignore function type attributes (PR #118420)

Robert Dazi via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 12 16:37:52 PST 2024


https://github.com/v01dXYZ updated https://github.com/llvm/llvm-project/pull/118420

>From b6f013097c0003e37800ad13b420e50e3c84511b Mon Sep 17 00:00:00 2001
From: v01dxyz <v01dxyz at v01d.xyz>
Date: Tue, 3 Dec 2024 04:52:33 +0100
Subject: [PATCH 1/7] FunctionDecl::getFunctionTypeLoc: ignore function type
 attributes

---
 clang/lib/AST/Decl.cpp | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 741e908cf9bc56..7df66b3bb7e14d 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3876,8 +3876,17 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
 
 FunctionTypeLoc FunctionDecl::getFunctionTypeLoc() const {
   const TypeSourceInfo *TSI = getTypeSourceInfo();
-  return TSI ? TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>()
-             : FunctionTypeLoc();
+
+  if (!TSI)
+    return FunctionTypeLoc();
+
+  TypeLoc TL = TSI->getTypeLoc().IgnoreParens();
+
+  // ignore function type attributes
+  while (auto ATL = TL.getAs<AttributedTypeLoc>())
+    TL = ATL.getModifiedLoc();
+
+  return TL.getAs<FunctionTypeLoc>();
 }
 
 SourceRange FunctionDecl::getReturnTypeSourceRange() const {

>From d5faa43a7e9c27d9493b9a171fe4d283952a5103 Mon Sep 17 00:00:00 2001
From: v01dxyz <v01dxyz at v01d.xyz>
Date: Sun, 8 Dec 2024 02:16:44 +0100
Subject: [PATCH 2/7] tmp: Add test and replace ignore parens by getAsAdjusted

---
 clang/lib/AST/Decl.cpp           |  8 +------
 clang/unittests/AST/AttrTest.cpp | 40 ++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 7df66b3bb7e14d..2ec5f5753427de 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3880,13 +3880,7 @@ FunctionTypeLoc FunctionDecl::getFunctionTypeLoc() const {
   if (!TSI)
     return FunctionTypeLoc();
 
-  TypeLoc TL = TSI->getTypeLoc().IgnoreParens();
-
-  // ignore function type attributes
-  while (auto ATL = TL.getAs<AttributedTypeLoc>())
-    TL = ATL.getModifiedLoc();
-
-  return TL.getAs<FunctionTypeLoc>();
+  return TSI->getTypeLoc().getAsAdjusted<FunctionTypeLoc>();
 }
 
 SourceRange FunctionDecl::getReturnTypeSourceRange() const {
diff --git a/clang/unittests/AST/AttrTest.cpp b/clang/unittests/AST/AttrTest.cpp
index 46c3f5729021ec..6cf879c4012510 100644
--- a/clang/unittests/AST/AttrTest.cpp
+++ b/clang/unittests/AST/AttrTest.cpp
@@ -86,6 +86,9 @@ TEST(Attr, AnnotateType) {
     struct S { int mem; };
     int [[clang::annotate_type("int")]]
     S::* [[clang::annotate_type("ptr_to_mem")]] ptr_to_member = &S::mem;
+
+    // Function Type Attributes
+    __attribute__((noreturn)) int f_noreturn();
   )cpp");
 
   {
@@ -153,6 +156,42 @@ TEST(Attr, AnnotateType) {
     EXPECT_EQ(IntTL.getType(), AST->getASTContext().IntTy);
   }
 
+  {
+    const FunctionDecl *Func = getFunctionNode(AST.get(), "f_noreturn");
+    const FunctionTypeLoc FTL = Func->getFunctionTypeLoc();
+    const FunctionType *FT = FTL.getTypePtr();
+
+    EXPECT_TRUE(FT->getExtInfo().getNoReturn());
+  }
+
+  // The following test verifies getFunctionTypeLoc returns a type
+  // which takes into account the attribute (instead of only the nake
+  // type).
+  //
+  // This is hard to do with C/C++ because it seems using a function
+  // type attribute with a C/C++ -function declaration only results
+  // with either:
+  //
+  // 1. It does NOT produce any AttributedType (for example it only
+  //   sets one flag of the FunctionType's ExtInfo, ie NoReturn).
+  // 2. It produces an AttributedType with modified type and
+  //   equivalent type that are equal (for example, that's what
+  //   happens with Calling Convention attributes).
+  //
+  // Fortunately, ObjC has one specific function type attribute that
+  // creates an AttributedType with different modified type and
+  // equivalent type.
+  auto AST_ObjC = buildASTFromCodeWithArgs(R"objc(
+    __attribute__((ns_returns_retained)) id f();
+  )objc", {"-fobjc-arc",}, "input.mm");
+  {
+    const FunctionDecl *f = getFunctionNode(AST_ObjC.get(), "f");
+    const FunctionTypeLoc FTL = f->getFunctionTypeLoc();
+
+    const FunctionType *FT = FTL.getTypePtr();
+    EXPECT_TRUE(FT->getExtInfo().getProducesResult());
+  }
+
   // Test type annotation on an `__auto_type` type in C mode.
   AST = buildASTFromCodeWithArgs(R"c(
     __auto_type [[clang::annotate_type("auto")]] auto_var = 1;
@@ -166,6 +205,7 @@ TEST(Attr, AnnotateType) {
     AutoTypeLoc AutoTL;
     AssertAnnotatedAs(Var->getTypeSourceInfo()->getTypeLoc(), "auto", AutoTL);
   }
+
 }
 
 TEST(Attr, RegularKeywordAttribute) {

>From 7e647b98756f64fbcaccba808dae2abaf9bdb2d1 Mon Sep 17 00:00:00 2001
From: v01dxyz <v01dxyz at v01d.xyz>
Date: Sun, 8 Dec 2024 02:55:33 +0100
Subject: [PATCH 3/7] tmp: getAsAdjusted use getModifiedLoc, replace the loop
 by a custom one

---
 clang/lib/AST/Decl.cpp | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 2ec5f5753427de..110ef70562c72d 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3880,7 +3880,19 @@ FunctionTypeLoc FunctionDecl::getFunctionTypeLoc() const {
   if (!TSI)
     return FunctionTypeLoc();
 
-  return TSI->getTypeLoc().getAsAdjusted<FunctionTypeLoc>();
+  TypeLoc TL = TSI->getTypeLoc();
+  FunctionTypeLoc FTL;
+
+  while (!(FTL = TL.getAs<FunctionTypeLoc>())) {
+    if (auto PTL = TL.getAs<ParenTypeLoc>())
+      TL = PTL.getInnerLoc();
+    else if (auto ATL = TL.getAs<AttributedTypeLoc>())
+      TL = ATL.getEquivalentTypeLoc();
+    else
+      break;
+  }
+
+  return FTL;
 }
 
 SourceRange FunctionDecl::getReturnTypeSourceRange() const {

>From 21af94db316b2e827eeff04880e53f933c22c806 Mon Sep 17 00:00:00 2001
From: v01dxyz <v01dxyz at v01d.xyz>
Date: Sun, 8 Dec 2024 03:00:32 +0100
Subject: [PATCH 4/7] tmp: fix test

---
 clang/unittests/AST/AttrTest.cpp | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/clang/unittests/AST/AttrTest.cpp b/clang/unittests/AST/AttrTest.cpp
index 6cf879c4012510..9fc1a294529b0b 100644
--- a/clang/unittests/AST/AttrTest.cpp
+++ b/clang/unittests/AST/AttrTest.cpp
@@ -181,9 +181,12 @@ TEST(Attr, AnnotateType) {
   // Fortunately, ObjC has one specific function type attribute that
   // creates an AttributedType with different modified type and
   // equivalent type.
-  auto AST_ObjC = buildASTFromCodeWithArgs(R"objc(
+  auto AST_ObjC = buildASTFromCodeWithArgs(
+      R"objc(
     __attribute__((ns_returns_retained)) id f();
-  )objc", {"-fobjc-arc",}, "input.mm");
+  )objc",
+      {"-fobjc-arc", "-fsyntax-only", "-fobjc-runtime=macosx-10.7"},
+      "input.mm");
   {
     const FunctionDecl *f = getFunctionNode(AST_ObjC.get(), "f");
     const FunctionTypeLoc FTL = f->getFunctionTypeLoc();
@@ -205,7 +208,6 @@ TEST(Attr, AnnotateType) {
     AutoTypeLoc AutoTL;
     AssertAnnotatedAs(Var->getTypeSourceInfo()->getTypeLoc(), "auto", AutoTL);
   }
-
 }
 
 TEST(Attr, RegularKeywordAttribute) {

>From f125b5e91a3c9fdd11077fe6acd4044128e6c2a3 Mon Sep 17 00:00:00 2001
From: v01dxyz <v01dxyz at v01d.xyz>
Date: Wed, 11 Dec 2024 14:32:26 +0100
Subject: [PATCH 5/7] tmp: fix typos, add tests

---
 clang/unittests/AST/AttrTest.cpp | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/clang/unittests/AST/AttrTest.cpp b/clang/unittests/AST/AttrTest.cpp
index 9fc1a294529b0b..6ba07d01c4096c 100644
--- a/clang/unittests/AST/AttrTest.cpp
+++ b/clang/unittests/AST/AttrTest.cpp
@@ -89,6 +89,7 @@ TEST(Attr, AnnotateType) {
 
     // Function Type Attributes
     __attribute__((noreturn)) int f_noreturn();
+    __attribute__((preserve_most)) int f_cc_preserve_most();
   )cpp");
 
   {
@@ -161,7 +162,15 @@ TEST(Attr, AnnotateType) {
     const FunctionTypeLoc FTL = Func->getFunctionTypeLoc();
     const FunctionType *FT = FTL.getTypePtr();
 
-    EXPECT_TRUE(FT->getExtInfo().getNoReturn());
+    EXPECT_TRUE(FT->getNoReturnAttr());
+  }
+
+  {
+    const FunctionDecl *Func = getFunctionNode(AST.get(), "f_cc_preserve_most");
+    const FunctionTypeLoc FTL = Func->getFunctionTypeLoc();
+    const FunctionType *FT = FTL.getTypePtr();
+
+    EXPECT_TRUE(FT->getCallConv() == CC_PreserveMost);
   }
 
   // The following test verifies getFunctionTypeLoc returns a type
@@ -169,7 +178,7 @@ TEST(Attr, AnnotateType) {
   // type).
   //
   // This is hard to do with C/C++ because it seems using a function
-  // type attribute with a C/C++ -function declaration only results
+  // type attribute with a C/C++ function declaration only results
   // with either:
   //
   // 1. It does NOT produce any AttributedType (for example it only

>From 6d749da8e531cdf3336717e39a2ddbb13233070f Mon Sep 17 00:00:00 2001
From: v01dxyz <v01dxyz at v01d.xyz>
Date: Wed, 11 Dec 2024 17:11:41 +0100
Subject: [PATCH 6/7] Fix clangd test

---
 .../clangd/unittests/InlayHintTests.cpp            | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
index 77d78b8777fe30..030e4995777060 100644
--- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
+++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
@@ -1577,19 +1577,21 @@ TEST(TypeHints, Aliased) {
 }
 
 TEST(TypeHints, CallingConvention) {
-  // Check that we don't crash for lambdas without a FunctionTypeLoc
+  // Check that we don't crash for lambdas with an annotation
   // https://github.com/clangd/clangd/issues/2223
-  std::string Code = R"cpp(
+  Annotations Source(R"cpp(
     void test() {
-      []() __cdecl {};
+      []($lambda[[)]]__cdecl {};
     }
-  )cpp";
-  TestTU TU = TestTU::withCode(Code);
+  )cpp");
+  TestTU TU = TestTU::withCode(Source.code());
   TU.ExtraArgs.push_back("--target=x86_64-w64-mingw32");
   TU.PredefineMacros = true; // for the __cdecl
   auto AST = TU.build();
 
-  EXPECT_THAT(hintsOfKind(AST, InlayHintKind::Type), IsEmpty());
+  EXPECT_THAT(
+      hintsOfKind(AST, InlayHintKind::Type),
+      ElementsAre(HintMatcher(ExpectedHint{"-> void", "lambda"}, Source)));
 }
 
 TEST(TypeHints, Decltype) {

>From 3d18b0868193e56eef1b97ca67a59a55953ebd86 Mon Sep 17 00:00:00 2001
From: v01dxyz <v01dxyz at v01d.xyz>
Date: Fri, 13 Dec 2024 01:35:26 +0100
Subject: [PATCH 7/7] Support MacroQualifiedTypeLoc, fix typos

---
 clang/lib/AST/Decl.cpp           |  6 ++++--
 clang/unittests/AST/AttrTest.cpp | 28 +++++++++++++++++++++++++++-
 2 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 110ef70562c72d..dcc2240c599b9c 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3884,10 +3884,12 @@ FunctionTypeLoc FunctionDecl::getFunctionTypeLoc() const {
   FunctionTypeLoc FTL;
 
   while (!(FTL = TL.getAs<FunctionTypeLoc>())) {
-    if (auto PTL = TL.getAs<ParenTypeLoc>())
+    if (const auto PTL = TL.getAs<ParenTypeLoc>())
       TL = PTL.getInnerLoc();
-    else if (auto ATL = TL.getAs<AttributedTypeLoc>())
+    else if (const auto ATL = TL.getAs<AttributedTypeLoc>())
       TL = ATL.getEquivalentTypeLoc();
+    else if (const auto MQTL = TL.getAs<MacroQualifiedTypeLoc>())
+      TL = MQTL.getInnerLoc();
     else
       break;
   }
diff --git a/clang/unittests/AST/AttrTest.cpp b/clang/unittests/AST/AttrTest.cpp
index 6ba07d01c4096c..eb3cf0a64d7741 100644
--- a/clang/unittests/AST/AttrTest.cpp
+++ b/clang/unittests/AST/AttrTest.cpp
@@ -90,6 +90,19 @@ TEST(Attr, AnnotateType) {
     // Function Type Attributes
     __attribute__((noreturn)) int f_noreturn();
     __attribute__((preserve_most)) int f_cc_preserve_most();
+
+    #define PRESERVE_MOST __attribute__((preserve_most))
+    PRESERVE_MOST int f_macro_attribue();
+
+    int (__attribute__((preserve_most)) f_paren_attribute)();
+
+    int (
+      PRESERVE_MOST
+      (
+        __attribute__((warn_unused_result))
+        (f_w_paren_and_attr)
+      )
+    ) ();
   )cpp");
 
   {
@@ -173,6 +186,19 @@ TEST(Attr, AnnotateType) {
     EXPECT_TRUE(FT->getCallConv() == CC_PreserveMost);
   }
 
+  {
+    for(auto should_have_func_type_loc: {
+	"f_macro_attribue",
+	"f_paren_attribute",
+	"f_w_paren_and_attr",
+      }) {
+      llvm::errs() << "O: " << should_have_func_type_loc << "\n";
+      const FunctionDecl *Func = getFunctionNode(AST.get(), should_have_func_type_loc);
+
+      EXPECT_TRUE(Func->getFunctionTypeLoc());
+    }
+  }
+
   // The following test verifies getFunctionTypeLoc returns a type
   // which takes into account the attribute (instead of only the nake
   // type).
@@ -182,7 +208,7 @@ TEST(Attr, AnnotateType) {
   // with either:
   //
   // 1. It does NOT produce any AttributedType (for example it only
-  //   sets one flag of the FunctionType's ExtInfo, ie NoReturn).
+  //   sets one flag of the FunctionType's ExtInfo, e.g. NoReturn).
   // 2. It produces an AttributedType with modified type and
   //   equivalent type that are equal (for example, that's what
   //   happens with Calling Convention attributes).



More information about the cfe-commits mailing list