get_offset_range() expects integer and pointer arguments but can't deal with others such as C++ OFFSET_TYPE. The attached fix has the function fail for arguments of such types. I have committed the trivial change in r11-6328 after regression-testing in on x86_64-linux.
Martin
commit fdd8560cce9f10fe5dcd26483440be136b81701d Author: Martin Sebor <mse...@redhat.com> Date: Wed Dec 23 16:28:06 2020 -0700 PR c++/98413 - ICE on placement new and member pointer gcc/ChangeLog: PR c++/98413 * builtins.c (get_offset_range): Avoid non-integers/-pointers. gcc/testsuite/ChangeLog: PR c++/98413 * g++.dg/warn/pr98413.C: New test. diff --git a/gcc/builtins.c b/gcc/builtins.c index 28e44445ab2..498a1121dec 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -5097,6 +5097,8 @@ get_offset_range (tree x, gimple *stmt, offset_int r[2], range_query *rvals) x = TREE_OPERAND (x, 0); tree type = TREE_TYPE (x); + if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) + return false; if (TREE_CODE (x) != INTEGER_CST && TREE_CODE (x) != SSA_NAME) @@ -13398,6 +13400,7 @@ warn_dealloc_offset (location_t loc, tree exp, const access_ref &aref) return false; tree dealloc_decl = get_callee_fndecl (exp); + if (DECL_IS_OPERATOR_DELETE_P (dealloc_decl) && !DECL_IS_REPLACEABLE_OPERATOR (dealloc_decl)) { diff --git a/gcc/testsuite/g++.dg/warn/pr98413.C b/gcc/testsuite/g++.dg/warn/pr98413.C new file mode 100644 index 00000000000..877871ad2c4 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/pr98413.C @@ -0,0 +1,23 @@ +/* PR c++/98413 - ICE on placement new and member pointer + { dg-do compile } + { dg-options "-Wall" } */ + +void* operator new (__SIZE_TYPE__, void *p) { return p; } + +struct A { int m; } a; + +void fc (int A::*p) +{ + new (&(a.*p)) char; +} + +void fi (int A::*p) +{ + new (&(a.*p)) int; +} + +void fB (int A::*p) +{ + struct B { int a[2]; }; + new (&(a.*p)) B; // { dg-warning "\\\[-Wplacement-new" } +}