Skip to content

Reapply 19c708c "FunctionDecl::getFunctionTypeLoc: ignore function type attributes (#118420)" #136484

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 21, 2025

Conversation

resistor
Copy link
Collaborator

@resistor resistor commented Apr 20, 2025

Avoid using PreservesMost in the testcase as it is not supported on all targets.

Original PR #118290.

…pe attributes (llvm#118420)"

Avoid using PreservesMost in the testcase as it is not supported on all targets.

Original PR llvm#118290.

---------

Co-authored-by: v01dxyz <v01dxyz@v01d.xyz>
Co-authored-by: Owen Anderson <resistor@mac.com>
@llvmbot llvmbot added clang Clang issues not falling into any other category clang-tools-extra clangd clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Apr 20, 2025
@resistor resistor requested a review from erichkeane April 20, 2025 12:03
@llvmbot
Copy link
Member

llvmbot commented Apr 20, 2025

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-clangd

@llvm/pr-subscribers-clang-tools-extra

Author: Owen Anderson (resistor)

Changes

Avoid using PreservesMost in the testcase as it is not supported on all targets.

Original PR #118290.


Full diff: https://github.com/llvm/llvm-project/pull/136484.diff

3 Files Affected:

  • (modified) clang-tools-extra/clangd/unittests/InlayHintTests.cpp (+8-6)
  • (modified) clang/lib/AST/Decl.cpp (+19-2)
  • (modified) clang/unittests/AST/AttrTest.cpp (+69)
diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp
index 77d78b8777fe3..030e499577706 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) {
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index ad1cb01592e9b..1d9208f0e1c72 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3910,8 +3910,25 @@ 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();
+  FunctionTypeLoc FTL;
+
+  while (!(FTL = TL.getAs<FunctionTypeLoc>())) {
+    if (const auto PTL = TL.getAs<ParenTypeLoc>())
+      TL = PTL.getInnerLoc();
+    else if (const auto ATL = TL.getAs<AttributedTypeLoc>())
+      TL = ATL.getEquivalentTypeLoc();
+    else if (const auto MQTL = TL.getAs<MacroQualifiedTypeLoc>())
+      TL = MQTL.getInnerLoc();
+    else
+      break;
+  }
+
+  return FTL;
 }
 
 SourceRange FunctionDecl::getReturnTypeSourceRange() const {
diff --git a/clang/unittests/AST/AttrTest.cpp b/clang/unittests/AST/AttrTest.cpp
index 46c3f5729021e..bbf1c0f9a382b 100644
--- a/clang/unittests/AST/AttrTest.cpp
+++ b/clang/unittests/AST/AttrTest.cpp
@@ -86,6 +86,22 @@ 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();
+
+    #define NO_RETURN __attribute__((noreturn))
+    NO_RETURN int f_macro_attribue();
+
+    int (__attribute__((noreturn)) f_paren_attribute)();
+
+    int (
+      NO_RETURN
+      (
+        __attribute__((warn_unused_result))
+        (f_w_paren_and_attr)
+      )
+    ) ();
   )cpp");
 
   {
@@ -153,6 +169,59 @@ 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->getNoReturnAttr());
+  }
+
+  {
+    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).
+  //
+  // 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, 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).
+  //
+  // 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", "-fsyntax-only", "-fobjc-runtime=macosx-10.7"},
+      "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;

@resistor resistor requested a review from HighCommander4 April 20, 2025 12:03
Copy link

⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo.
Please turn off Keep my email addresses private setting in your account.
See LLVM Discourse for more information.

@resistor resistor merged commit 6d765e1 into llvm:main Apr 21, 2025
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category clang-tools-extra clangd
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants