diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 2c0c3a8dc2f9d..3bb82c1572ef9 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 f4ba2bc3c6de3..2a3a29bd2ee1c 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 : SubsetSubjectgetFunctionType(true) != nullptr && - isa(S->getFunctionType())) || + isa(S->getFunctionType())) || isa(S) || isa(S)}], "non-K&R-style functions">; diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index c0a331d18cab8..fc16448cf9e90 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()->getPointeeType(); + else if (Ty->isMemberFunctionPointerType()) + Ty = Ty->castAs()->getPointeeType(); else if (Ty->isFunctionReferenceType()) Ty = Ty->castAs()->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 a9bca6778d0f1..77826f8f9af09 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 0000000000000..ee784c816a060 --- /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 0000000000000..80067500284b1 --- /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))));