Given template <typename T> void foo () { T A::*fptr; }
We don't know whether fptr is a pointer-to-member-function or a pointer-to-data-member until we know what T is. But until then, fptr gets the type OFFSET_TYPE. If we later instantiate foo with e.g. T = void() then we know that fptr is a pointer-to-member-function and so we give the specialized copy of fptr a type which satisfies TYPE_PTRMEMFUNC_P (some RECORD_TYPE). The placeholder OFFSET_TYPE and the resulting RECORD_TYPE however have different sizes and modes (DI vs TI on x86_64), but the DECL_MODE of the specialized copy of fptr never gets updated accordingly. This stale DECL_MODE eventually leads the backend to miscompile copies to and from fptr. [ Some more analysis at https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70096#c4 ] This patch makes tsubst_decl clear the DECL_MODE of the new decl so that the subsequent call to layout_type can update it accordingly. Tested on x86_64-pc-linux-gnu. Does this patch look OK to commit? gcc/cp/ChangeLog: PR c++/70096 * pt.c (tsubst_decl): Clear the DECL_MODE of the new decl. gcc/testsuite/ChangeLog: PR c++/70096 * g++.dg/template/ptrmem30.C: New test. --- gcc/cp/pt.c | 2 ++ gcc/testsuite/g++.dg/template/ptrmem30.C | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 gcc/testsuite/g++.dg/template/ptrmem30.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f9c5b0b..ebfc45b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12374,6 +12374,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) /* The initializer must not be expanded until it is required; see [temp.inst]. */ DECL_INITIAL (r) = NULL_TREE; + if (VAR_P (r)) + DECL_MODE (r) = VOIDmode; if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_WRTL)) SET_DECL_RTL (r, NULL); DECL_SIZE (r) = DECL_SIZE_UNIT (r) = 0; diff --git a/gcc/testsuite/g++.dg/template/ptrmem30.C b/gcc/testsuite/g++.dg/template/ptrmem30.C new file mode 100644 index 0000000..923238b --- /dev/null +++ b/gcc/testsuite/g++.dg/template/ptrmem30.C @@ -0,0 +1,45 @@ +// PR c++/70096 +// { dg-do run } + +int read; + +struct Holder +{ + void foo () { read = data; } + int data; +}; + +void +poison_stack () +{ + volatile char a[256]; + __builtin_memset ((void *)a, 0xa, sizeof a); +} + +template <typename F> +void test1 () +{ + Holder h; + h.data = 42; + F Holder::*fptr = &Holder::foo; + (h.*fptr)(); +} + +template <typename F> +void test2 () +{ + Holder h; + h.data = 42; + F Holder::*fptr1 = &Holder::foo; + F Holder::*fptr2 = fptr1; + (h.*fptr2)(); +} + + +int main () +{ + poison_stack (); + test1<void()>(); + poison_stack (); + test2<void()>(); +} -- 2.8.0.rc3.27.gade0865