diff --git a/src/expr.c b/src/expr.c index 1813fd078d..9314f3f146 100644 --- a/src/expr.c +++ b/src/expr.c @@ -19143,6 +19143,43 @@ called from outside of the expression-processing routines. } /* scan_type_returning_type_trait_operator */ +an_expr_node_ptr take_typeof_operands(a_type_ptr tp) +/* +tp is a variably modified type used in an expression (e.g., as the type of a +cast). Return the operands of any C typeof operators in tp whose evaluation +is still pending (see typeof_operand_pending), combined with comma operators, +or NULL if there are none, and mark them as no longer pending. A typedef in +tp stops the search: a use of a typedef does not repeat the evaluation of the +typeof operands in its definition. +*/ +{ + an_expr_node_ptr inits = NULL; + + while (is_variably_modified_type(tp)) { + if (tp->kind == (a_type_kind)tk_typeref) { + if (typeref_is_typedef(tp)) break; + if (tp->variant.typeref.typeof_operand_pending) { + an_expr_node_ptr expr = decltype_arg(tp); + check_assertion(expr != NULL); + tp->variant.typeref.typeof_operand_pending = FALSE; + if (expr->is_lvalue) expr = add_address_of_to_node(expr); + inits = inits == NULL ? expr : make_comma_node(inits, expr); + } /* if */ + tp = tp->variant.typeref.type; + } else if (tp->kind == (a_type_kind)tk_pointer) { + tp = tp->variant.pointer.type; + } else if (tp->kind == (a_type_kind)tk_array) { + tp = tp->variant.array.element_type; + } else if (tp->kind == (a_type_kind)tk_routine) { + tp = tp->variant.routine.return_type; + } else { + break; + } /* if */ + } /* while */ + return inits; +} /* take_typeof_operands */ + + a_type_ptr scan_typeof_operator(a_rescan_control_block *rcblock, ARG_UNUSED a_decl_pos_block *decl_pos_block) /* @@ -19189,6 +19226,10 @@ the expression-processing routines. an_expr_node_ptr saved_decltype_rescan_operand = NULL; a_boolean is_unqual_variant = curr_token == tok_typeof_unqual; +#if DO_IL_LOWERING + unsigned long saved_error_count = + diagnostic_counters.total.errors; +#endif /* DO_IL_LOWERING */ parens_optional = gpp_mode && gnu_version >= 30400; /* Note that, unlike e.g. sizeof, typeof can appear directly in a declarative @@ -19378,6 +19419,45 @@ the expression-processing routines. prep_generic_operand(&operand); } /* if */ expr = make_node_from_operand(&operand); +#if DO_IL_LOWERING + if (C_mode() && vla_enabled && rcblock == NULL && + is_variably_modified_type(result) && + diagnostic_counters.total.errors == saved_error_count && + node_has_side_effects(expr, (a_boolean *)NULL) && + !type_has_side_effects(result)) { + /* The operand has a variably modified type, so it is evaluated + (C23 6.7.3.6). As for sizeof, the expression scanned above (as + an unevaluated operand) is kept and evaluated at run time. This + is needed only when the IL is lowered: a back end that generates + source (e.g., the C++-generating back end) reproduces the typeof + itself, and the compiler of that source evaluates its operand. + The dimension expressions of the resulting type are evaluated + wherever that type is used, so the operand is evaluated only if + it has side effects of its own and those dimensions have none + (e.g., "typeof(++n, (int (*)[n])p)"); otherwise the evaluation + of a dimension expression would be repeated. */ + if (saved_expr_stack != NULL) { + /* Expression contexts defer evaluation to VLA lowering. */ + typeof_type->variant.typeref.typeof_operand_pending = TRUE; + } else if (depth_stmt_stack >= 0 && + !scope_is(&scope_stack_top(), sck_func_prototype)) { + /* A declaration in a block evaluates the type specifier once, + before any declarator bounds or initializers, even if the + declaration has several declarators. */ + a_statement_ptr stmt = add_statement_at_stmt_pos( + stmk_expr, + &operand.position, + /*compiler_generated=*/TRUE); + stmt->expr = expr; + set_expr_result_not_used(expr); + } else { + /* A parameter declaration (or a declaration outside of any + function, which is an error for a variably modified type). + No statement can be added here, so the operand is not + evaluated. */ + } /* if */ + } /* if */ +#endif /* DO_IL_LOWERING */ if (!dependent_arg) { /* Check for cases where the result type is not dependent but the expression is instantiation-dependent. */ @@ -30469,6 +30549,18 @@ just an expression in parentheses. Return the scanned expression in &type_position, type_cast_to); } /* if */ +#if DO_IL_LOWERING + if (C_mode() && !err && is_variably_modified_type(type_cast_to)) { + an_expr_node_ptr type_inits = take_typeof_operands(type_cast_to); + if (type_inits != NULL) { + /* Preserve the execution point before conditional folding. */ + make_expression_operand( + make_comma_node(type_inits, + make_node_from_operand(result)), result); + rule_out_expr_kinds(ROEK_INTEGRAL_CONSTANT, result); + } /* if */ + } /* if */ +#endif /* DO_IL_LOWERING */ } /* if */ set_operand_position(result, &start_position, &end_position, &start_position); diff --git a/src/expr.h b/src/expr.h index ab79604b05..decd3324f6 100644 --- a/src/expr.h +++ b/src/expr.h @@ -927,6 +927,7 @@ extern a_type_ptr scan_pack_index_type_specifier( extern a_type_ptr scan_typeof_operator(a_rescan_control_block *rcblock, a_decl_pos_block *decl_pos_block); +extern an_expr_node_ptr take_typeof_operands(a_type_ptr tp); #if GNU_EXTENSIONS_ALLOWED diff --git a/src/il_alloc.c b/src/il_alloc.c index 0d590dfa02..94024114dd 100644 --- a/src/il_alloc.c +++ b/src/il_alloc.c @@ -2157,6 +2157,7 @@ to default values. pte->variant.typeref.explicit_memory_attribute_made_implicit = FALSE; #endif /* NEAR_AND_FAR_ALLOWED */ pte->variant.typeref.has_variably_modified_type = FALSE; + pte->variant.typeref.typeof_operand_pending = FALSE; #if LOWER_VARIABLE_LENGTH_ARRAYS pte->variant.typeref.is_lowered_variably_modified_type = FALSE; #endif /* LOWER_VARIABLE_LENGTH_ARRAYS */ diff --git a/src/il_def.h b/src/il_def.h index 43470cfc6b..e02f9b3f38 100644 --- a/src/il_def.h +++ b/src/il_def.h @@ -10774,6 +10774,12 @@ typedef struct a_type { has_variably_modified_type:1; /* The type referred to is a variably modified type, i.e., is or contains a VLA type. */ + a_bit_field + typeof_operand_pending:1; + /* The typeof operand (in C) has a variably modified + type, so it must be evaluated where this type is + used in an expression (e.g., in a cast). Set to + FALSE once that evaluation has been emitted. */ #if LOWER_VARIABLE_LENGTH_ARRAYS a_bit_field is_lowered_variably_modified_type:1; diff --git a/src/il_display.c b/src/il_display.c index 9145ed239d..f5bc605151 100644 --- a/src/il_display.c +++ b/src/il_display.c @@ -2738,6 +2738,9 @@ Display the indicated type entry. if (ptr->variant.typeref.has_variably_modified_type) { disp_boolean("has_variably_modified_type", TRUE); } /* if */ + if (ptr->variant.typeref.typeof_operand_pending) { + disp_boolean("typeof_operand_pending", TRUE); + } /* if */ #if BACK_END_IS_CP_GEN_BE if (ptr->variant.typeref.surrounding_name_linkage_state != (a_name_linkage_kind)nlk_none) { diff --git a/src/lower_c99.c b/src/lower_c99.c index a6005bade3..68ddd8de36 100644 --- a/src/lower_c99.c +++ b/src/lower_c99.c @@ -433,6 +433,10 @@ variables also make indexing into the VLA arrays more efficient. an_expr_node_ptr inits = NULL, accums = NULL; a_type_ptr ptrdiff_type = integer_type(targ_ptrdiff_t_int_kind); + inits = take_typeof_operands(tp); + if (inits != NULL) { + lower_any_expr(inits); + } /* if */ /* There may be multiple multilevel VLA components in a type. For example: int (*const (a[n][n]))[m][m]; The outer loop deals with that possibility. */ @@ -699,6 +703,11 @@ memory for it. */ { a_variable_ptr vla_var; + an_expr_node_ptr type_inits; + a_type_ptr declared_type = stmt->variant.vla.is_typedef_decl ? + stmt->variant.vla.variant.typedef_type->variant.typeref.type : + stmt->variant.vla.variant.variable->type; + type_inits = lower_vla_dimensions(declared_type); if (stmt->variant.vla.is_typedef_decl) { vla_var = NULL; @@ -710,6 +719,10 @@ memory for it. if (vla_var != NULL && vla_var->is_vla) { stmt->expr = make_vla_allocation_expr(vla_var); } /* if */ + if (type_inits != NULL) { + stmt->expr = stmt->expr == NULL ? type_inits : + make_comma_node(type_inits, stmt->expr); + } /* if */ if (stmt->expr == NULL) { /* This may happen for simple VLA typedefs. Create a dummy expression. */ stmt->expr = node_for_host_large_integer((a_host_large_integer)0, diff --git a/src/pending_changes/edg-28891-typeof-evaluation.txt b/src/pending_changes/edg-28891-typeof-evaluation.txt new file mode 100644 index 0000000000..f10b38aeba --- /dev/null +++ b/src/pending_changes/edg-28891-typeof-evaluation.txt @@ -0,0 +1,13 @@ +[GH #457] +GNU C: typeof operands of variably modified type were not evaluated + +When the operand of a GNU C typeof (or C23 typeof) operator has a variably +modified type, the operand must be evaluated. The front end treated it as +unevaluated, so its side effects were lost. The operand is now evaluated +once where the declaration or cast appears (not once per declarator, and not +again when a typedef for the type is used). For example, with --gnu_version: + + int n = 1, a[8]; + void f(void) { + typeof (++n, (int (*)[n])a) p, q; // n is now 2. + } diff --git a/tests/expectations/edg_x86_32_cp/regressions.log b/tests/expectations/edg_x86_32_cp/regressions.log index abd2f80e25..c29cba0419 100644 --- a/tests/expectations/edg_x86_32_cp/regressions.log +++ b/tests/expectations/edg_x86_32_cp/regressions.log @@ -1,3 +1,4 @@ +edg-28891.sft.c:rp:-DTEST_NUMBER=1:REQUIREMENTS NOT MET: gh-183-redecl.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:REQUIREMENTS NOT MET: gh-309-diag.sft.cpp:fp:-DTEST_NUMBER=1 --g++:REQUIREMENTS NOT MET:Diagnostic position of implicit destructor calls at scope exit gh-309-diag.sft.cpp:fp:-DTEST_NUMBER=2 --g++ --no_exceptions:REQUIREMENTS NOT MET:Diagnostic position of implicit destructor calls at scope exit diff --git a/tests/expectations/edg_x86_64/imported.log b/tests/expectations/edg_x86_64/imported.log index fbbfdb7f73..ad7ba2914a 100644 --- a/tests/expectations/edg_x86_64/imported.log +++ b/tests/expectations/edg_x86_64/imported.log @@ -3414,7 +3414,6 @@ gnu/c/pr113262.sft.c:fn:-DTEST_NUMBER=1:FAIL: gnu/c/pr113492.sft.c:fp:-DTEST_NUMBER=1 --c23:FAIL: gnu/c/pr113596.sft.c:rp:-DTEST_NUMBER=1:FAIL: gnu/c/pr114090.sft.c:rp:-DTEST_NUMBER=1:FAIL: -gnu/c/pr114831-2.sft.c:rp:-DTEST_NUMBER=1 --c23:FAIL: gnu/c/pr115109.sft.c:fp:-DTEST_NUMBER=1 --c23:FAIL: gnu/c/pr115426.sft.c:fp:-DTEST_NUMBER=1 --c11 --strict_gnu:FAIL: gnu/c/pr116034.sft.c:rp:-DTEST_NUMBER=1:FAIL(COMPILE): diff --git a/tests/expectations/edg_x86_64_cp/regressions.log b/tests/expectations/edg_x86_64_cp/regressions.log index abd2f80e25..c29cba0419 100644 --- a/tests/expectations/edg_x86_64_cp/regressions.log +++ b/tests/expectations/edg_x86_64_cp/regressions.log @@ -1,3 +1,4 @@ +edg-28891.sft.c:rp:-DTEST_NUMBER=1:REQUIREMENTS NOT MET: gh-183-redecl.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:REQUIREMENTS NOT MET: gh-309-diag.sft.cpp:fp:-DTEST_NUMBER=1 --g++:REQUIREMENTS NOT MET:Diagnostic position of implicit destructor calls at scope exit gh-309-diag.sft.cpp:fp:-DTEST_NUMBER=2 --g++ --no_exceptions:REQUIREMENTS NOT MET:Diagnostic position of implicit destructor calls at scope exit diff --git a/tests/tests/imported/gnu/c/.gnu99-const-expr-3.rto/default.1.1.txt b/tests/tests/imported/gnu/c/.gnu99-const-expr-3.rto/default.1.1.txt index 009f218827..2240ab7b82 100644 --- a/tests/tests/imported/gnu/c/.gnu99-const-expr-3.rto/default.1.1.txt +++ b/tests/tests/imported/gnu/c/.gnu99-const-expr-3.rto/default.1.1.txt @@ -26,6 +26,10 @@ fe_only -DTEST_NUMBER=1 --gnu_version=999999 -e 200 --no_wrap --no_wrap_diagnost static int (*a7)[n] = (__typeof__((int (*)[n])sa + m++))sa; /* { dg-error "constant" } */ ^ +"Test_name.c", line 32: error: expression must have a constant value + static int (*a7)[n] = (__typeof__((int (*)[n])sa + m++))sa; /* { dg-error "constant" } */ + ^ + "Test_name.c", line 26: warning: variable "a1" was declared but never referenced static int (*a1)[n] = &sa; ^ @@ -54,4 +58,4 @@ fe_only -DTEST_NUMBER=1 --gnu_version=999999 -e 200 --no_wrap --no_wrap_diagnost static int (*a7)[n] = (__typeof__((int (*)[n])sa + m++))sa; /* { dg-error "constant" } */ ^ -6 errors detected in the compilation of "Test_name.c". +7 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/gnu/c/.gnu99-const-expr-3.rto/edg_x86_32_cp.1.1.txt b/tests/tests/imported/gnu/c/.gnu99-const-expr-3.rto/edg_x86_32_cp.1.1.txt new file mode 100644 index 0000000000..009f218827 --- /dev/null +++ b/tests/tests/imported/gnu/c/.gnu99-const-expr-3.rto/edg_x86_32_cp.1.1.txt @@ -0,0 +1,57 @@ +fe_only -DTEST_NUMBER=1 --gnu_version=999999 -e 200 --no_wrap --no_wrap_diagnostics --gcc --c99 --strict_gnu Test_name.c +"Test_name.c", line 27: error: expression must have a constant value + static int (*a2)[n] = (__typeof__(int (*)[n]))sa; + ^ +"Test_name.c", line 27: note: the value of parameter "n" (declared at line 24) cannot be used as a constant + static int (*a2)[n] = (__typeof__(int (*)[n]))sa; + ^ + +"Test_name.c", line 28: error: a compound literal is not allowed in an integral constant expression + static int (*a3)[n] = (__typeof__(int (*)[(int){m++}]))sa; /* { dg-error "constant" } */ + ^ + +"Test_name.c", line 28: error: this operator is not allowed in a constant expression + static int (*a3)[n] = (__typeof__(int (*)[(int){m++}]))sa; /* { dg-error "constant" } */ + ^ + +"Test_name.c", line 29: error: expression must have a constant value + static int (*a4)[n] = (__typeof__((int (*)[n])sa))sa; + ^ + +"Test_name.c", line 30: error: expression must have a constant value + static int (*a5)[n] = (__typeof__((int (*)[m++])sa))sa; /* { dg-error "constant" } */ + ^ + +"Test_name.c", line 32: error: expression must have a constant value + static int (*a7)[n] = (__typeof__((int (*)[n])sa + m++))sa; /* { dg-error "constant" } */ + ^ + +"Test_name.c", line 26: warning: variable "a1" was declared but never referenced + static int (*a1)[n] = &sa; + ^ + +"Test_name.c", line 27: warning: variable "a2" was declared but never referenced + static int (*a2)[n] = (__typeof__(int (*)[n]))sa; + ^ + +"Test_name.c", line 28: warning: variable "a3" was declared but never referenced + static int (*a3)[n] = (__typeof__(int (*)[(int){m++}]))sa; /* { dg-error "constant" } */ + ^ + +"Test_name.c", line 29: warning: variable "a4" was declared but never referenced + static int (*a4)[n] = (__typeof__((int (*)[n])sa))sa; + ^ + +"Test_name.c", line 30: warning: variable "a5" was declared but never referenced + static int (*a5)[n] = (__typeof__((int (*)[m++])sa))sa; /* { dg-error "constant" } */ + ^ + +"Test_name.c", line 31: warning: variable "a6" was declared but never referenced + static int (*a6)[n] = (__typeof__((int (*)[100])(int (*)[m++])sa))sa; + ^ + +"Test_name.c", line 32: warning: variable "a7" was declared but never referenced + static int (*a7)[n] = (__typeof__((int (*)[n])sa + m++))sa; /* { dg-error "constant" } */ + ^ + +6 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/gnu/c/.gnu99-const-expr-3.rto/edg_x86_64_cp.1.1.txt b/tests/tests/imported/gnu/c/.gnu99-const-expr-3.rto/edg_x86_64_cp.1.1.txt new file mode 100644 index 0000000000..009f218827 --- /dev/null +++ b/tests/tests/imported/gnu/c/.gnu99-const-expr-3.rto/edg_x86_64_cp.1.1.txt @@ -0,0 +1,57 @@ +fe_only -DTEST_NUMBER=1 --gnu_version=999999 -e 200 --no_wrap --no_wrap_diagnostics --gcc --c99 --strict_gnu Test_name.c +"Test_name.c", line 27: error: expression must have a constant value + static int (*a2)[n] = (__typeof__(int (*)[n]))sa; + ^ +"Test_name.c", line 27: note: the value of parameter "n" (declared at line 24) cannot be used as a constant + static int (*a2)[n] = (__typeof__(int (*)[n]))sa; + ^ + +"Test_name.c", line 28: error: a compound literal is not allowed in an integral constant expression + static int (*a3)[n] = (__typeof__(int (*)[(int){m++}]))sa; /* { dg-error "constant" } */ + ^ + +"Test_name.c", line 28: error: this operator is not allowed in a constant expression + static int (*a3)[n] = (__typeof__(int (*)[(int){m++}]))sa; /* { dg-error "constant" } */ + ^ + +"Test_name.c", line 29: error: expression must have a constant value + static int (*a4)[n] = (__typeof__((int (*)[n])sa))sa; + ^ + +"Test_name.c", line 30: error: expression must have a constant value + static int (*a5)[n] = (__typeof__((int (*)[m++])sa))sa; /* { dg-error "constant" } */ + ^ + +"Test_name.c", line 32: error: expression must have a constant value + static int (*a7)[n] = (__typeof__((int (*)[n])sa + m++))sa; /* { dg-error "constant" } */ + ^ + +"Test_name.c", line 26: warning: variable "a1" was declared but never referenced + static int (*a1)[n] = &sa; + ^ + +"Test_name.c", line 27: warning: variable "a2" was declared but never referenced + static int (*a2)[n] = (__typeof__(int (*)[n]))sa; + ^ + +"Test_name.c", line 28: warning: variable "a3" was declared but never referenced + static int (*a3)[n] = (__typeof__(int (*)[(int){m++}]))sa; /* { dg-error "constant" } */ + ^ + +"Test_name.c", line 29: warning: variable "a4" was declared but never referenced + static int (*a4)[n] = (__typeof__((int (*)[n])sa))sa; + ^ + +"Test_name.c", line 30: warning: variable "a5" was declared but never referenced + static int (*a5)[n] = (__typeof__((int (*)[m++])sa))sa; /* { dg-error "constant" } */ + ^ + +"Test_name.c", line 31: warning: variable "a6" was declared but never referenced + static int (*a6)[n] = (__typeof__((int (*)[100])(int (*)[m++])sa))sa; + ^ + +"Test_name.c", line 32: warning: variable "a7" was declared but never referenced + static int (*a7)[n] = (__typeof__((int (*)[n])sa + m++))sa; /* { dg-error "constant" } */ + ^ + +6 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.edg-28891-params.rto/default.1.1.txt b/tests/tests/regressions/.edg-28891-params.rto/default.1.1.txt new file mode 100644 index 0000000000..5349d2a14c --- /dev/null +++ b/tests/tests/regressions/.edg-28891-params.rto/default.1.1.txt @@ -0,0 +1 @@ +eccp -DTEST_NUMBER=1 --c --c11 --no_strict_gnu --gnu_version=130300 Test_name.c diff --git a/tests/tests/regressions/.edg-28891-params.rto/default.1.2.txt b/tests/tests/regressions/.edg-28891-params.rto/default.1.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/.edg-28891-params.rto/default.1.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/.edg-28891-single.rto/default.1.1.txt b/tests/tests/regressions/.edg-28891-single.rto/default.1.1.txt new file mode 100644 index 0000000000..5349d2a14c --- /dev/null +++ b/tests/tests/regressions/.edg-28891-single.rto/default.1.1.txt @@ -0,0 +1 @@ +eccp -DTEST_NUMBER=1 --c --c11 --no_strict_gnu --gnu_version=130300 Test_name.c diff --git a/tests/tests/regressions/.edg-28891-single.rto/default.1.2.txt b/tests/tests/regressions/.edg-28891-single.rto/default.1.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/.edg-28891-single.rto/default.1.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/.edg-28891.rto/default.1.1.txt b/tests/tests/regressions/.edg-28891.rto/default.1.1.txt new file mode 100644 index 0000000000..5349d2a14c --- /dev/null +++ b/tests/tests/regressions/.edg-28891.rto/default.1.1.txt @@ -0,0 +1 @@ +eccp -DTEST_NUMBER=1 --c --c11 --no_strict_gnu --gnu_version=130300 Test_name.c diff --git a/tests/tests/regressions/.edg-28891.rto/default.1.2.txt b/tests/tests/regressions/.edg-28891.rto/default.1.2.txt new file mode 100644 index 0000000000..ff2642c6d5 --- /dev/null +++ b/tests/tests/regressions/.edg-28891.rto/default.1.2.txt @@ -0,0 +1 @@ +./a.out diff --git a/tests/tests/regressions/edg-28891-params.sft.c b/tests/tests/regressions/edg-28891-params.sft.c new file mode 100644 index 0000000000..eff599662f --- /dev/null +++ b/tests/tests/regressions/edg-28891-params.sft.c @@ -0,0 +1,11 @@ +//type:rp +//options_all:--c --c11 --no_strict_gnu --gnu_version=130300 +// A typeof operand of variably modified type in a block-scope function +// prototype is not evaluated, and must not be inserted as a statement. +int a[8]; +int main(void) { + int m = 2; + void local_proto(typeof (++m, (int (*)[m])a) p); + void local_proto2(int n, typeof (++m, (int (*)[m])a) *p, int q[m]); + return m != 2; +} diff --git a/tests/tests/regressions/edg-28891-single.sft.c b/tests/tests/regressions/edg-28891-single.sft.c new file mode 100644 index 0000000000..eb44a48610 --- /dev/null +++ b/tests/tests/regressions/edg-28891-single.sft.c @@ -0,0 +1,21 @@ +//type:rp +//options_all:--c --c11 --no_strict_gnu --gnu_version=130300 +// Each typeof operand of variably modified type is evaluated exactly once +// (with any back end): declarations with one declarator, a typedef, and a +// cast. +int main(void) { + int k = 1, a[8], fails = 0; + typeof (++k, (int (*)[k])a) p; + (void)sizeof(p); + fails += k != 2; + typedef typeof (++k, (int (*)[k])a) T; + T t; + (void)sizeof(t); + fails += k != 3; + (void)(typeof (++k, (int (*)[k])a))a; + fails += k != 4; + typeof ((({ ++k; 0; }), (int (*)[k])a)) s; + (void)sizeof(s); + fails += k != 5; + return fails; +} diff --git a/tests/tests/regressions/edg-28891.sft.c b/tests/tests/regressions/edg-28891.sft.c new file mode 100644 index 0000000000..0494d2573d --- /dev/null +++ b/tests/tests/regressions/edg-28891.sft.c @@ -0,0 +1,34 @@ +//type:rp +//require:DO_IL_LOWERING 1 +//options_all:--c --c11 --no_strict_gnu --gnu_version=130300 +// With a source-generating back end, the typeof is reproduced and the run-time +// behavior is that of the compiler of the generated code. +int main(void) { + int k = 1, a[8], fails = 0; + typeof (++k, (int (*)[k])a) p; + (void)sizeof(p); + fails += k != 2; + // The type specifier is evaluated once per declaration, not once per + // declarator (GCC PR c/124576). + typeof (++k, (int (*)[k])a) q, r; + (void)sizeof(q); (void)sizeof(r); + fails += k != 3; + typedef typeof (++k, (int (*)[k])a) T; + fails += k != 4; + T t; + (void)sizeof(t); + fails += k != 4; // A typedef use must not repeat its defining expression. + typeof (++k, (int*)a) ordinary; + (void)sizeof(ordinary); + fails += k != 4; // A non-variably-modified operand is unevaluated. + (void)(typeof (++k, (int (*)[k])a))a; + fails += k != 5; + // A statement expression nested in the operand is evaluated once too. + typeof ((({ ++k; 0; }), (int (*)[k])a)) s, u; + (void)sizeof(s); (void)sizeof(u); + fails += k != 6; + (void)sizeof(typeof (++k, (int (*)[k])a)); + // sizeof a pointer does not require evaluating its variably modified type. + // GNU C is permitted to omit that evaluation, so do not constrain k here. + return fails; +}