[clang] [clang-tools-extra] FunctionDecl::getFunctionTypeLoc: ignore function type attributes (PR #118420)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Dec 16 06:26:58 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Robert Dazi (v01dXYZ)
<details>
<summary>Changes</summary>
Related to #<!-- -->118290.
---
Full diff: https://github.com/llvm/llvm-project/pull/118420.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 (+78)
``````````diff
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) {
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 741e908cf9bc56..dcc2240c599b9c 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3876,8 +3876,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 46c3f5729021ec..3be362895b77e8 100644
--- a/clang/unittests/AST/AttrTest.cpp
+++ b/clang/unittests/AST/AttrTest.cpp
@@ -86,6 +86,23 @@ 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();
+ __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");
{
@@ -153,6 +170,67 @@ 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());
+ }
+
+ {
+ 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);
+ }
+
+ {
+ 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;
``````````
</details>
https://github.com/llvm/llvm-project/pull/118420
More information about the cfe-commits
mailing list