https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82186
--- Comment #5 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Note C++ ICEs as well on the same testcase. The problem (I guess for both FEs) is from where to emit the DECL_EXPRs, e.g. in the C FE groktypename is called from many spots and I believe the middle-end wants to see DECL_EXPRs not just for the toplevel variably_modified_type_p (e.g. from c_cast_expr), but also any VLA types it refers to, if they don't have DECL_EXPRs emitted yet. I don't think either FE tracks that right now. Or shall we try to emit those later (e.g. from C genericization), if we see a variably modified type that doesn't have a TYPE_DECL yet add somewhere (before the stmt containing it? What about conditional contexts etc.?) a DECL_EXPR for the TYPE_DECL we create for it. E.g. for: int foo (int n, void *x, void *y) { struct S { int (***p)[n][n][n]; } s; int (***q)[n][n][n]; s.p = x; q = y; return (***s.p)[1][2][3] + (***q)[1][2][3]; } we emit all the needed DECL_EXPRs, apparently from: /* When the pointed-to type involves components of variable size, care must be taken to ensure that the size evaluation code is emitted early enough to dominate all the possible later uses and late enough for the variables on which it depends to have been assigned. This is expected to happen automatically when the pointed-to type has a name/declaration of it's own, but special attention is required if the type is anonymous. We handle the NORMAL and FIELD contexts here by attaching an artificial TYPE_DECL to such pointed-to type. This forces the sizes evaluation at a safe point and ensures it is not deferred until e.g. within a deeper conditional context. We expect nothing to be needed here for PARM or TYPENAME. Pushing a TYPE_DECL at this point for TYPENAME would actually be incorrect, as we might be in the middle of an expression with side effects on the pointed-to type size "arguments" prior to the pointer declaration point and the fake TYPE_DECL in the enclosing context would force the size evaluation prior to the side effects. */ if (!TYPE_NAME (type) && (decl_context == NORMAL || decl_context == FIELD) && variably_modified_type_p (type, NULL_TREE)) { tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type); DECL_ARTIFICIAL (decl) = 1; pushdecl (decl); finish_decl (decl, loc, NULL_TREE, NULL_TREE, NULL_TREE); TYPE_NAME (type) = decl; } in grokdeclarator. The reason why this doesn't trigger in the cast case is that it uses groktypename which sets decl_context to TYPENAME. Now, I can understand in some cases we don't want any DECL_EXPRs, e.g. in sizeof, alignof, _Alignas. But in C case we as this testcase shows need it. What about _Atomic ( type-name ), typeof, generic, va_arg, offsetof, types_compatible_p, ObjC at encode, compound literals? There is also OpenMP UDR (though, perhaps that doesn't want them, for them to be used one needs a compatible type to be somewhere else for it to match). So, shall groktypename have a boolean or similar arg whether it wants them or not and shall we use separate decl_context for TYPENAME which would add the DECL_EXPRs and e.g. SIZEOF which wouldn't?