int main() { struct S { int m; }; return sizeof(char[S::m]); } $ g++ prog.cc prog.cc: In function 'int main()': prog.cc:4:27: internal compiler error: in gimplify_expr, at gimplify.c:14581 4 | return sizeof(char[S::m]); | ~~~^ 0x5c6160 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) ../../source/gcc/gimplify.c:14581 0x9a7434 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) ../../source/gcc/gimplify.c:13885 0x9a7de0 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) ../../source/gcc/gimplify.c:13702 0x9aa19f gimplify_compound_lval ../../source/gcc/gimplify.c:3064 0x9a6c00 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) ../../source/gcc/gimplify.c:13533 0x9a7434 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) ../../source/gcc/gimplify.c:13885 0x9a7129 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) ../../source/gcc/gimplify.c:14348 0x9abfb0 internal_get_tmp_var ../../source/gcc/gimplify.c:619 0x9ac749 get_initialized_tmp_var(tree_node*, gimple**, gimple**, bool) ../../source/gcc/gimplify.c:674 0x9ac749 gimplify_save_expr ../../source/gcc/gimplify.c:6072 0x9a7621 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) ../../source/gcc/gimplify.c:13881 0x9a7434 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) ../../source/gcc/gimplify.c:13885 0x9a7129 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) ../../source/gcc/gimplify.c:14348 0x9a7434 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) ../../source/gcc/gimplify.c:13885 0x9b1ecb gimplify_modify_expr ../../source/gcc/gimplify.c:5765 0x9a73a2 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) ../../source/gcc/gimplify.c:13581 0x9acc8e gimplify_stmt(tree_node**, gimple**) ../../source/gcc/gimplify.c:6822 0x9acc8e gimplify_and_add(tree_node*, gimple**) ../../source/gcc/gimplify.c:486 0x9acc8e gimplify_return_expr ../../source/gcc/gimplify.c:1667 0x9a8303 gimplify_expr(tree_node**, gimple**, gimple**, bool (*)(tree_node*), int) ../../source/gcc/gimplify.c:13842 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions. (https://wandbox.org/permlink/GNNTjXAK2pQ5clUt) I've selectively checked about some of g++ versions, from 4.4.7 to HEAD, on wandbox.org. They're all crashing, just segfaulting before 5.1.0 and ICEing in gimplify_expr starting from 5.1.0.
GCC thinks that `char[S::m]` is VLA (because the lvalue-to-rvalue conversion on `S::m` lvalue doesn't look like a constant expression) and tries to move the evaluation of `sizeof(char[S::m])` to run time. $ g++ prog.cc -pedantic prog.cc: In function 'int main()': prog.cc:4:28: warning: ISO C++ forbids variable length array [-Wvla] 4 | return sizeof(char[S::m]); | ^ prog.cc:4:27: internal compiler error: in gimplify_expr, at gimplify.c:14581 4 | return sizeof(char[S::m]); | ...
Confirmed. Bisection points to r210692 committed into 4.10.0: gcc/ * tree.def (VOID_CST): New. * tree-core.h (TI_VOID): New. * tree.h (void_node): New. * tree.c (tree_node_structure_for_code, tree_code_size) (iterative_hash_expr): Handle VOID_CST. (build_common_tree_nodes): Initialize void_node. gcc/c-family/ * c-common.h (CTI_VOID_ZERO, void_zero_node): Delete. * c-common.c (c_common_nodes_and_builtins): Don't initialize void_zero_node. * c-pretty-print.c (pp_c_void_constant): New function. (c_pretty_printer::constant, c_pretty_printer::primary_expression) (c_pretty_printer::expression): Handle VOID_CST. * cilk.c (extract_free_variables): Likewise. * c-ubsan.c (ubsan_instrument_division, ubsan_instrument_shift) (ubsan_instrument_vla): Use void_node instead of void_zero_node. gcc/c/ * c-array-notation.c (expand_array_notations): Use void_node instead of void_zero_node. gcc/cp/ * cvt.c (convert_to_void): Use void_node instead of void_zero_node. * cp-array-notation.c (replace_invariant_exprs): Likewise. (expand_array_notation): Handle VOID_CST. * error.c (dump_expr): Likewise. * cxx-pretty-print.c (cxx_pretty_printer::primary_expression) (cxx_pretty_printer::expression): Likewise. (pp_cxx_new_expression): Use void_node instead of void_zero_node. * decl.c (register_dtor_fn): Likewise. * init.c (build_raw_new_expr, build_new_1, build_vec_init) (build_delete, push_base_cleanups): Likewise. * mangle.c (write_expression): Likewise. * semantics.c (finish_break_stmt, empty_expr_stmt_p): Likewise. * pt.c (tsubst_decl, tsubst_copy_and_build): Likewise. (tsubst, tsubst_copy, build_non_dependent_expr): Handle VOID_CST. * tree.c (cp_tree_equal): Likewise. (build_dummy_object, is_dummy_object, stabilize_expr): Use void_node instead of void_zero_node. * typeck.c (check_return_expr): Likewise. * typeck2.c (build_functional_cast): Likewise.
Hmm, yeah. Before the patch we silently accepted the code and generated an unconditional trap for a null dereference, which doesn't sound right either. This is because we used to fold the dummy object pointer (represented using an INTEGER_CST with void_type) into a normal null pointer. Where should this be trapped? The error for accessing a non-static data member is suppressed for sizeof, and obviously needs to be for sizeof(S::m): /* DR 613/850: Can use non-static data members without an associated object in sizeof/decltype/alignof. */ if (is_dummy_object (object) && cp_unevaluated_operand == 0 && (!processing_template_decl || !current_class_ref)) A see-one-play-one fix would be to force cp_unevaluated_operand to zero while parsing an array dimension, on the basis that the dimension should either be constant (standard C++) or can be evaluated (GNU VLAs). That feels really hackish though... Should we instead trap this during gimplification? But then that would probably make: sizeof(char[sizeof(char[S::m])]) valid, which doesn't sound right either.
Related to c++/84939
GCC 8.4.0 has been released, adjusting target milestone.
Jason, your thoughts on this?
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:9b53edc796d284b6adec7f2996772dbddf4c341e commit r11-8181-g9b53edc796d284b6adec7f2996772dbddf4c341e Author: Jason Merrill <jason@redhat.com> Date: Wed Apr 14 09:30:05 2021 -0400 c++: non-static member, array bound, sizeof [PR93314] N2253 allowed referring to non-static data members without an object in unevaluated operands like that of sizeof, but in a constant-expression context like an array bound or template argument within such an unevaluated operand we do actually need a value, so that permission cannot apply. gcc/cp/ChangeLog: PR c++/93314 * semantics.c (finish_id_expression_1): Clear cp_unevaluated_operand for a non-static data member in a constant-expression. gcc/testsuite/ChangeLog: PR c++/93314 * g++.dg/parse/uneval1.C: New test.
Fixed for 11 so far.
Created attachment 50594 [details] patch for stage 1 A more general, but also more risky, fix for next stage 1.
GCC 8 branch is being closed.
The releases/gcc-11 branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:b786dafe9eb933f23686c68c6d7110fef5656985 commit r11-8430-gb786dafe9eb933f23686c68c6d7110fef5656985 Author: Jason Merrill <jason@redhat.com> Date: Wed Apr 14 11:24:50 2021 -0400 c++: constant expressions are evaluated [PR93314] My GCC 11 patch for PR93314 turned off cp_unevaluated_operand while processing an id-expression that names a non-static data member, but the broader issue is that in general, a constant-expression is evaluated even in an unevaluated operand. This also fixes 100205, introduced by the earlier patch that couldn't distinguish between the different allow_non_constant_p cases. PR c++/100205 PR c++/93314 gcc/cp/ChangeLog: * cp-tree.h (cp_evaluated): Add reset parm to constructor. * parser.c (cp_parser_constant_expression): Change allow_non_constant_p to int. Use cp_evaluated. (cp_parser_initializer_clause): Pass 2 to allow_non_constant_p. * semantics.c (finish_id_expression_1): Don't mess with cp_unevaluated_operand here. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/decltype-nonstatic1.C: New test.
GCC 9.4 is being released, retargeting bugs to GCC 9.5.
GCC 9 branch is being closed
GCC 10.4 is being released, retargeting bugs to GCC 10.5.
Fixed in GCC 11.