In this testcase, ctx->object was the array subobject and 'this' refers to the containing object, so we failed. Fixed by generalizing PLACEHOLDER_EXPR handling more (in a way that replace_placeholders_r already handles).
Tested x86_64-pc-linux-gnu, applying to trunk.
commit a383ab56e2ea367509255f5a6b95fb5ad0b20f88 Author: Jason Merrill <ja...@redhat.com> Date: Wed Mar 8 16:03:14 2017 -0500 PR c++/79797 - ICE with self-reference in array DMI. * constexpr.c (lookup_placeholder): Split out... (cxx_eval_constant_expression): ...from here. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index f114da0..2510e23e 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3827,6 +3827,35 @@ cxx_eval_switch_expr (const constexpr_ctx *ctx, tree t, return NULL_TREE; } +/* Find the object of TYPE under initialization in CTX. */ + +static tree +lookup_placeholder (const constexpr_ctx *ctx, bool lval, tree type) +{ + if (!ctx || !ctx->ctor || (lval && !ctx->object)) + return NULL_TREE; + + /* We could use ctx->object unconditionally, but using ctx->ctor when we + can is a minor optimization. */ + if (!lval && same_type_p (TREE_TYPE (ctx->ctor), type)) + return ctx->ctor; + + /* Since an object cannot have a field of its own type, we can search outward + from ctx->object to find the unique containing object of TYPE. */ + tree ob = ctx->object; + while (ob) + { + if (same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (ob), type)) + break; + if (handled_component_p (ob)) + ob = TREE_OPERAND (ob, 0); + else + ob = NULL_TREE; + } + + return ob; +} + /* Attempt to reduce the expression T to a constant value. On failure, issue diagnostic and return error_mark_node. */ /* FIXME unify with c_fully_fold */ @@ -4468,27 +4497,15 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, break; case PLACEHOLDER_EXPR: - if (!ctx || !ctx->ctor || (lval && !ctx->object) - || !(same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (t), TREE_TYPE (ctx->ctor)))) - { - /* A placeholder without a referent. We can get here when - checking whether NSDMIs are noexcept, or in massage_init_elt; - just say it's non-constant for now. */ - gcc_assert (ctx->quiet); - *non_constant_p = true; - break; - } - else - { - /* Use of the value or address of the current object. We could - use ctx->object unconditionally, but using ctx->ctor when we - can is a minor optimization. */ - tree ctor = lval ? ctx->object : ctx->ctor; - return cxx_eval_constant_expression - (ctx, ctor, lval, - non_constant_p, overflow_p); - } + /* Use of the value or address of the current object. */ + if (tree ctor = lookup_placeholder (ctx, lval, TREE_TYPE (t))) + return cxx_eval_constant_expression (ctx, ctor, lval, + non_constant_p, overflow_p); + /* A placeholder without a referent. We can get here when + checking whether NSDMIs are noexcept, or in massage_init_elt; + just say it's non-constant for now. */ + gcc_assert (ctx->quiet); + *non_constant_p = true; break; case EXIT_EXPR: diff --git a/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C new file mode 100644 index 0000000..2134ac9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr7.C @@ -0,0 +1,12 @@ +// PR c++/79797 +// { dg-do compile { target c++14 } } + +struct A +{ + A* x[1]{(A*)this}; +}; + +extern constexpr A a{}; + +#define SA(X) static_assert ((X), #X) +SA (a.x[0] == &a);