-
Notifications
You must be signed in to change notification settings - Fork 14.3k
release/20.x: [clang] Support member function poiners in Decl::getFunctionType() (#125077) #125956
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
Conversation
…lvm#125077) This seems consistent with the documentation, which claims it: ``` /// Looks through the Decl's underlying type to extract a FunctionType /// when possible. Will return null if the type underlying the Decl does not /// have a FunctionType. const FunctionType *getFunctionType(bool BlocksToo = true) const; ``` Note: This patch rewords this doc comment to clarify it includes various function pointer types. Without this, attaching attributes (which use `HasFunctionProto`) to member function pointers errors with: ``` error: '<attr>' only applies to non-K&R-style functions ``` ...which does not really make sense, since member functions are not K&C functions. With this change the Arm SME TypeAttrs work correctly on member function pointers. Note, however, that not all attributes work correctly when applied to function pointers or member function pointers. For example, `alloc_align` crashes when applied to a function pointer (on truck): https://godbolt.org/z/YvMhnhKfx (as it only expects a `FunctionDecl` not a `ParmVarDecl`). The same crash applies to member function pointers (for the same reason). (cherry picked from commit 692c9b2)
@efriedma-quic What do you think about merging this PR to the release branch? |
@llvm/pr-subscribers-clang Author: None (llvmbot) ChangesBackport 692c9b2 Requested by: @MacDue Full diff: https://github.com/llvm/llvm-project/pull/125956.diff 6 Files Affected:
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 2c0c3a8dc2f9d5..3bb82c1572ef9c 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -1257,8 +1257,11 @@ class alignas(8) Decl {
int64_t getID() const;
/// Looks through the Decl's underlying type to extract a FunctionType
- /// when possible. Will return null if the type underlying the Decl does not
- /// have a FunctionType.
+ /// when possible. This includes direct FunctionDecls, along with various
+ /// function types and typedefs. This includes function pointers/references,
+ /// member function pointers, and optionally if \p BlocksToo is set
+ /// Objective-C block pointers. Returns nullptr if the type underlying the
+ /// Decl does not have a FunctionType.
const FunctionType *getFunctionType(bool BlocksToo = true) const;
// Looks through the Decl's underlying type to determine if it's a
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index f4ba2bc3c6de31..2a3a29bd2ee1cf 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -198,7 +198,7 @@ def OpenCLKernelFunction
// inclusive nature of subject testing).
def HasFunctionProto : SubsetSubject<DeclBase,
[{(S->getFunctionType(true) != nullptr &&
- isa<FunctionProtoType>(S->getFunctionType())) ||
+ isa<FunctionProtoType>(S->getFunctionType())) ||
isa<ObjCMethodDecl>(S) ||
isa<BlockDecl>(S)}],
"non-K&R-style functions">;
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 8506b95f761fe5..adf6053392db37 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -1203,6 +1203,8 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const {
if (Ty->isFunctionPointerType())
Ty = Ty->castAs<PointerType>()->getPointeeType();
+ else if (Ty->isMemberFunctionPointerType())
+ Ty = Ty->castAs<MemberPointerType>()->getPointeeType();
else if (Ty->isFunctionReferenceType())
Ty = Ty->castAs<ReferenceType>()->getPointeeType();
else if (BlocksToo && Ty->isBlockPointerType())
diff --git a/clang/test/AST/attr-print-emit.cpp b/clang/test/AST/attr-print-emit.cpp
index a9bca6778d0f1a..77826f8f9af098 100644
--- a/clang/test/AST/attr-print-emit.cpp
+++ b/clang/test/AST/attr-print-emit.cpp
@@ -91,3 +91,8 @@ ANNOTATE_ATTR NONNULL_ATTR void fn_non_null_annotated_attr(int *) __attribute__(
[[gnu::nonnull(1)]] [[gnu::always_inline]] void cxx11_attr(int*) ANNOTATE_ATTR;
// CHECK: {{\[\[}}gnu::nonnull(1)]] {{\[\[}}gnu::always_inline]] void cxx11_attr(int *) __attribute__((annotate("Annotated")));
+
+struct Foo;
+
+// CHECK: void as_member_fn_ptr(int *(Foo::*member)(int) __attribute__((alloc_size(1))));
+void as_member_fn_ptr(int* (Foo::*member)(int) __attribute__((alloc_size(1))));
diff --git a/clang/test/CodeGen/AArch64/sme-attributes-member-function-pointer.cpp b/clang/test/CodeGen/AArch64/sme-attributes-member-function-pointer.cpp
new file mode 100644
index 00000000000000..ee784c816a0606
--- /dev/null
+++ b/clang/test/CodeGen/AArch64/sme-attributes-member-function-pointer.cpp
@@ -0,0 +1,37 @@
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -target-feature +sme2 -x c++ -std=c++20 -emit-llvm -o - %s | FileCheck %s --check-prefixes=CHECK
+
+struct TestStruct;
+
+__arm_new("za", "zt0") void test(TestStruct& TS,
+ void (TestStruct::*streaming_member_ptr)() __arm_streaming,
+ void (TestStruct::*streaming_compat_member)() __arm_streaming_compatible,
+ void (TestStruct::*arm_in_member)() __arm_in("za", "zt0"),
+ void (TestStruct::*arm_inout_member)() __arm_inout("za", "zt0"),
+ void (TestStruct::*arm_preserves_member)() __arm_preserves("za", "zt0"),
+ void (TestStruct::*arm_agnostic_member)() __arm_agnostic("sme_za_state")) {
+
+ // CHECK: call void %{{.*}} [[STREAMING_MEMBER_CALL_ATTRS:#.+]]
+ (TS.*streaming_member_ptr)();
+
+ // CHECK: call void %{{.*}} [[STREAMING_COMPAT_MEMBER_CALL_ATTRS:#.+]]
+ (TS.*streaming_compat_member)();
+
+ // CHECK: call void %{{.*}} [[ARM_IN_MEMBER_CALL_ATTRS:#.+]]
+ (TS.*arm_in_member)();
+
+ // CHECK: call void %{{.*}} [[ARM_INOUT_MEMBER_CALL_ATTRS:#.+]]
+ (TS.*arm_inout_member)();
+
+ // CHECK: call void %{{.*}} [[ARM_PRESERVES_MEMBER_CALL_ATTRS:#.+]]
+ (TS.*arm_preserves_member)();
+
+ // CHECK: call void %{{.*}} [[ARM_AGNOSTIC_MEMBER_CALL_ATTRS:#.+]]
+ (TS.*arm_agnostic_member)();
+}
+
+// CHECK: attributes [[STREAMING_MEMBER_CALL_ATTRS]] = { "aarch64_pstate_sm_enabled" }
+// CHECK: attributes [[STREAMING_COMPAT_MEMBER_CALL_ATTRS]] = { "aarch64_pstate_sm_compatible" }
+// CHECK: attributes [[ARM_IN_MEMBER_CALL_ATTRS]] = { "aarch64_in_za" "aarch64_in_zt0" }
+// CHECK: attributes [[ARM_INOUT_MEMBER_CALL_ATTRS]] = { "aarch64_inout_za" "aarch64_inout_zt0" }
+// CHECK: attributes [[ARM_PRESERVES_MEMBER_CALL_ATTRS]] = { "aarch64_preserves_za" "aarch64_preserves_zt0" }
+// CHECK: attributes [[ARM_AGNOSTIC_MEMBER_CALL_ATTRS]] = { "aarch64_za_state_agnostic" }
diff --git a/clang/test/CodeGen/xfail-alloc-align-fn-pointers.cpp b/clang/test/CodeGen/xfail-alloc-align-fn-pointers.cpp
new file mode 100644
index 00000000000000..80067500284b1e
--- /dev/null
+++ b/clang/test/CodeGen/xfail-alloc-align-fn-pointers.cpp
@@ -0,0 +1,10 @@
+
+// RUN: %clang_cc1 %s
+
+// FIXME: These should not crash!
+// XFAIL: *
+
+void aa_fn_ptr(char* (*member)(char*) __attribute__((alloc_align(1))));
+
+struct Test;
+void aa_member_fn_ptr(char* (Test::*member)(char*) __attribute__((alloc_align(1))));
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. This doesn't seem like a high priority to backport, but I guess it's safe enough for this point in the process.
@MacDue (or anyone else). If you would like to add a note about this fix in the release notes (completely optional). Please reply to this comment with a one or two sentence description of the fix. When you are done, please add the release:note label to this PR. |
Backport 692c9b2
Requested by: @MacDue