A middle-end change exposed that the C++ FE handling of pointer-to-member aggregates in cxx_get_alias_set isn't effective. The following patch makes it so by design by marking the structure members as not being aliased (there can be no pointers like &x.__pfn or &x.__delta) thus making them behave like fat pointers.
Bootstrapped and tested on x86_64-unknown-linux-gnu. OK for trunk and affected branches? Thanks, Richard. 2019-10-02 Richard Biener <rguent...@suse.de> PR c++/91606 * decl.c (build_ptrmemfunc_type): Mark pointer-to-member fat pointer structure members as DECL_NONADDRESSABLE_P. * g++.dg/torture/pr91606.C: New testcase. Index: gcc/cp/decl.c =================================================================== --- gcc/cp/decl.c (revision 276396) +++ gcc/cp/decl.c (working copy) @@ -9554,10 +9554,12 @@ build_ptrmemfunc_type (tree type) TYPE_PTRMEMFUNC_FLAG (t) = 1; field = build_decl (input_location, FIELD_DECL, pfn_identifier, type); + DECL_NONADDRESSABLE_P (field) = 1; fields = field; field = build_decl (input_location, FIELD_DECL, delta_identifier, delta_type_node); + DECL_NONADDRESSABLE_P (field) = 1; DECL_CHAIN (field) = fields; fields = field; Index: gcc/testsuite/g++.dg/torture/pr91606.C =================================================================== --- gcc/testsuite/g++.dg/torture/pr91606.C (revision 0) +++ gcc/testsuite/g++.dg/torture/pr91606.C (working copy) @@ -0,0 +1,109 @@ +/* { dg-do run } */ +/* { dg-additional-options "-fstrict-aliasing" } */ + +#include <cstdlib> +#include <array> +#include <type_traits> + +template <typename T1, typename T2> +struct variant +{ + constexpr variant(T1 arg) + : f1(arg), + index(0) + {} + + constexpr variant(T2 arg) + : f2(arg), + index(1) + {} + + union + { + T1 f1; + T2 f2; + }; + std::size_t index = 0; +}; + +template <typename T1, typename T2> +constexpr const T1* get_if(const variant<T1, T2>* v) +{ + if (v->index != 0) + { + return nullptr; + } + return &v->f1; +} + +template <typename T2, typename T1> +constexpr const T2* get_if(const variant<T1, T2>* v) +{ + if (v->index != 1) + { + return nullptr; + } + return &v->f2; +} + +template <typename T, size_t N> +struct my_array +{ + constexpr const T* begin() const + { + return data; + } + + constexpr const T* end() const + { + return data + N; + } + + T data[N]; +}; + +template <typename ...Ts> +constexpr auto get_array_of_variants(Ts ...ptrs) +{ + return std::array<variant<std::decay_t<Ts>...>, sizeof...(Ts)>{ ptrs... }; +} + +template <typename T> +constexpr auto get_member_functions(); + +template <typename Member, typename Class> +constexpr int getFuncId(Member (Class::*memFuncPtr)) +{ + int idx = 0u; + for (auto &anyFunc : get_member_functions<Class>()) + { + if (auto *specificFunc = get_if<Member (Class::*)>(&anyFunc)) + { + if (*specificFunc == memFuncPtr) + { + return idx; + } + } + ++idx; + } + std::abort(); +} + +struct MyStruct +{ + void fun1(int /*a*/) {} + + int fun2(char /*b*/, short /*c*/, bool /*d*/) { return 0; } + +}; + +template <> +constexpr auto get_member_functions<MyStruct>() +{ + return get_array_of_variants(&MyStruct::fun1, &MyStruct::fun2); +} + +int main() +{ + return getFuncId(&MyStruct::fun1); +}