From 8e7bac741b1ed9de5e877970a501ebb0c7531393 Mon Sep 17 00:00:00 2001 From: Ehab Maali <107338078+71iq@users.noreply.github.com> Date: Sat, 7 Nov 2026 23:15:45 +0200 Subject: [PATCH] Evaluate GNU C typeof operands of variably modified type [EDGcpfe/28891] The operand of a C typeof operator must be evaluated when it has a variably modified type, but it was treated as unevaluated, so its side effects were lost. When the IL is lowered, keep the operand (scanned as an unevaluated operand, as for sizeof) and evaluate it once: in a block-scope declaration, before the declarators; in an expression, where the cast that uses the type is evaluated. A use of a typedef does not repeat the evaluation, and nothing is evaluated in a parameter declaration. 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. A source-generating back end reproduces the typeof, so nothing is added for it. Add regression tests. gnu/c/pr114831-2 now passes, and gnu/c/gnu99-const-expr-3 gets the error its source expects. --- src/expr.c | 92 +++++++++++++++++++ src/expr.h | 1 + src/il_alloc.c | 1 + src/il_def.h | 6 ++ src/il_display.c | 3 + src/lower_c99.c | 13 +++ .../edg-28891-typeof-evaluation.txt | 13 +++ .../edg_x86_32_cp/regressions.log | 1 + tests/expectations/edg_x86_64/imported.log | 1 - .../edg_x86_64_cp/regressions.log | 1 + .../c/.gnu99-const-expr-3.rto/default.1.1.txt | 6 +- .../edg_x86_32_cp.1.1.txt | 57 ++++++++++++ .../edg_x86_64_cp.1.1.txt | 57 ++++++++++++ .../.edg-28891-params.rto/default.1.1.txt | 1 + .../.edg-28891-params.rto/default.1.2.txt | 1 + .../.edg-28891-single.rto/default.1.1.txt | 1 + .../.edg-28891-single.rto/default.1.2.txt | 1 + .../.edg-28891.rto/default.1.1.txt | 1 + .../.edg-28891.rto/default.1.2.txt | 1 + .../tests/regressions/edg-28891-params.sft.c | 11 +++ .../tests/regressions/edg-28891-single.sft.c | 21 +++++ tests/tests/regressions/edg-28891.sft.c | 34 +++++++ 22 files changed, 322 insertions(+), 2 deletions(-) create mode 100644 src/pending_changes/edg-28891-typeof-evaluation.txt create mode 100644 tests/tests/imported/gnu/c/.gnu99-const-expr-3.rto/edg_x86_32_cp.1.1.txt create mode 100644 tests/tests/imported/gnu/c/.gnu99-const-expr-3.rto/edg_x86_64_cp.1.1.txt create mode 100644 tests/tests/regressions/.edg-28891-params.rto/default.1.1.txt create mode 100644 tests/tests/regressions/.edg-28891-params.rto/default.1.2.txt create mode 100644 tests/tests/regressions/.edg-28891-single.rto/default.1.1.txt create mode 100644 tests/tests/regressions/.edg-28891-single.rto/default.1.2.txt create mode 100644 tests/tests/regressions/.edg-28891.rto/default.1.1.txt create mode 100644 tests/tests/regressions/.edg-28891.rto/default.1.2.txt create mode 100644 tests/tests/regressions/edg-28891-params.sft.c create mode 100644 tests/tests/regressions/edg-28891-single.sft.c create mode 100644 tests/tests/regressions/edg-28891.sft.c 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; +}