Skip to content

Commit fb582ed

Browse files
Momen-G-Ardaveedvdv-nvidia
authored andcommitted
Track GNU vector elements and apply Core issue 616 in C++11 modes [GH #90]
Constant evaluation now marks each element of a GNU vector as initialized when a whole vector value is stored (at the end of process_expr_work), and constexpr_copy_object_init_bits copies the state of each element. This fixes spurious "access to uninitialized object" errors when subscripting a vector member initialized from a vector value (e.g., Y(a).v[3]). To keep that sound, reading a whole vector (do_glvalue_to_prvalue) or copying an object that contains one now requires each element to be initialized, not only the first. When emulating GCC 9+ or Clang 4+, selecting a member of a class prvalue now produces an xvalue in C++11 mode too, as those compilers do. is_address_of_auto_object now also looks for temporaries on the addressing path, so returning a pointer into a member of a trivially destructible class prvalue (e.g., &make().arr[1]) is diagnosed. The re-recorded imported clang tests improve: cwg6xx loses three bogus cwg616 errors and expr.const/p2-0x gains its expected volatile error. In C++11 GNU mode, gnu cpp0x/decltype72 now passes, and gnu cpp26/name-independent-decl6 and clang C11/n1285 lose a few warnings, as in C++14 mode.
1 parent 0efcf62 commit fb582ed

37 files changed

Lines changed: 396 additions & 115 deletions

‎src/cmd_line.c‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4301,6 +4301,13 @@ default mode (e.g., exception handling).
43014301
std_override_modifiers_enabled = value;
43024302
constexpr_implies_const = value;
43034303
register_is_deprecated = TRUE;
4304+
if (value && rvalue_references_enabled &&
4305+
(cpp14_mode || gpp_mode || clang_mode) &&
4306+
!gpp_version_is(<90000) && !clangcpp_version_is(<40000)) {
4307+
/* A field selection on a class prvalue is an xvalue (CWG 616). GCC 9+
4308+
and Clang 4+ also do that in C++11 mode. */
4309+
selection_from_prvalue_is_xvalue = TRUE;
4310+
} /* if */
43044311
if (cpp14_mode) {
43054312
/* Features enabled in C++14 mode. */
43064313
if (auto_type_specifier_enabled) {
@@ -4317,11 +4324,6 @@ default mode (e.g., exception handling).
43174324
if (!option_kind_used[(int)optk_digit_separators]) {
43184325
digit_separators_enabled = TRUE;
43194326
} /* if */
4320-
if (rvalue_references_enabled &&
4321-
!gpp_version_is(<90000) && !clangcpp_version_is(<40000)) {
4322-
/* A field selection on a class prvalue is an xvalue (CWG 616). */
4323-
selection_from_prvalue_is_xvalue = TRUE;
4324-
} /* if */
43254327
relaxed_constexpr_enabled = TRUE;
43264328
sized_deallocation_enabled = RUNTIME_SUPPORTS_SIZED_DEALLOCATION;
43274329
if (gpp_mode && !clang_mode && gnu_version < 50000) {

‎src/cmd_line.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1742,7 +1742,8 @@ EXTERN_THREAD a_boolean
17421742
EXTERN_THREAD a_boolean
17431743
selection_from_prvalue_is_xvalue;
17441744
/* TRUE if a field selection on a prvalue class object
1745-
produces an xvalue (C++14 / CWG 616). When FALSE,
1745+
produces an xvalue (C++14 / CWG 616; GCC 9 and
1746+
Clang 4 also apply it in C++11 mode). When FALSE,
17461747
the selection is a prvalue. */
17471748

17481749
EXTERN_THREAD a_boolean

‎src/exprutil.c‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25482,9 +25482,12 @@ underlying entity is a temporary, return *is_temp set to TRUE.
2548225482
tblock.process_expr = examine_expr_for_auto_object;
2548325483
tblock.follow_addressing_path = TRUE;
2548425484
/* A pointer into a prvalue.field xvalue (CWG 616) addresses a
25485-
subobject of the class prvalue. */
25485+
subobject of the class prvalue, which is a temporary even when it
25486+
is not represented by an explicit temporary (e.g., for a trivially
25487+
destructible class). */
2548625488
tblock.follow_class_rvalue_addressing_path =
2548725489
selection_from_prvalue_is_xvalue;
25490+
tblock.look_for_temporaries = selection_from_prvalue_is_xvalue;
2548825491
traverse_expr(expr, &tblock);
2548925492
is_addr_of_auto = tblock.result;
2549025493
*is_temp = tblock.is_temp;

‎src/il_walk.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,8 @@ typedef struct an_expr_or_stmt_traversal_block {
387387
/* TRUE if expr_complete_object_type was called
388388
to determine the object type for a virtual function
389389
call. */
390-
/* Fields used by is_glvalue_for_auto_object: */
390+
/* Fields used by is_glvalue_for_auto_object and
391+
is_address_of_auto_object: */
391392
a_boolean is_temp;
392393
/* TRUE if the underlying object is a temporary. */
393394
a_boolean look_for_temporaries;

‎src/interpret.c‎

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4887,6 +4887,36 @@ object) is initialized.
48874887
} /* subobject_is_initialized */
48884888

48894889

4890+
#if GNU_VECTOR_TYPES_ALLOWED
4891+
static a_boolean vector_elements_are_initialized(
4892+
an_interpreter_state *ips,
4893+
a_type_ptr tp,
4894+
a_constexpr_address *cap)
4895+
/*
4896+
Return TRUE if each element of the vector of type tp at the address described
4897+
by *cap is initialized (or if the enclosing complete object is fully
4898+
initialized). The elements of a vector are tracked individually, so a whole
4899+
vector value can only be read if none of them is uninitialized.
4900+
*/
4901+
{
4902+
a_boolean result = TRUE;
4903+
4904+
if (!complete_object_is_initialized(cap->complete_object)) {
4905+
a_type_ptr etp = skip_typerefs(tp->variant.vector.element_type);
4906+
a_targ_size_t k, n_elems = num_vector_elements(tp);
4907+
a_byte_count elem_size = value_bytes_for_type(ips, etp, &result);
4908+
for (k = 0; result && k<n_elems; k += 1) {
4909+
if (!subobject_is_initialized(cap->address+k*elem_size,
4910+
cap->complete_object)) {
4911+
result = FALSE;
4912+
} /* if */
4913+
} /* for */
4914+
} /* if */
4915+
return result;
4916+
} /* vector_elements_are_initialized */
4917+
#endif /* GNU_VECTOR_TYPES_ALLOWED */
4918+
4919+
48904920
static a_boolean mark_mutable_members_not_initialized(
48914921
an_interpreter_state *ips,
48924922
a_byte *subobj,
@@ -7488,15 +7518,8 @@ END_DISABLE_GCC_WARNING_STR_OVERFLOW
74887518
/* A vector element can be accessed by itself (e.g., by
74897519
subscripting the member), so mark each element
74907520
initialized. */
7491-
a_type_ptr etp = skip_typerefs(
7492-
ftp->variant.vector.element_type);
7493-
a_targ_size_t k, n_elems = num_vector_elements(ftp);
7494-
a_byte_count elem_size = value_bytes_for_type(ips, etp,
7495-
&result);
7496-
for (k = 0; result && k<n_elems; k += 1) {
7497-
mark_subobject_initialized(dst_addr.address+k*elem_size,
7498-
complete_object);
7499-
} /* for */
7521+
mark_whole_subobject_initialized(ips, dst_addr.address, ftp,
7522+
complete_object);
75007523
} /* if */
75017524
#endif /* GNU_VECTOR_TYPES_ALLOWED */
75027525
elem_con = elem_con->next;
@@ -7834,6 +7857,25 @@ any subobject that is not initialized (the diagnostic is associated with pos).
78347857
} /* if */
78357858
}
78367859
break;
7860+
#if GNU_VECTOR_TYPES_ALLOWED
7861+
case tk_vector:
7862+
{ /* The elements of a vector are tracked individually: Handle each
7863+
element after the first (which shares the address of the vector
7864+
and was handled above). */
7865+
a_type_ptr etp = skip_typerefs(tp->variant.vector.element_type);
7866+
a_targ_size_t k, n_elems = num_vector_elements(tp);
7867+
a_byte_count elem_size = value_bytes_for_type(ips, etp, &result);
7868+
for (k = 1; result && k<n_elems; ++k) {
7869+
if (subobject_is_initialized(src_bytes+k*elem_size, complete_src)) {
7870+
mark_subobject_initialized(dst_bytes+k*elem_size, complete_dst);
7871+
} else {
7872+
do_constexpr_fail(result);
7873+
info_with_pos(ec_object_not_initialized, pos, ips);
7874+
} /* if */
7875+
} /* for */
7876+
}
7877+
break;
7878+
#endif /* GNU_VECTOR_TYPES_ALLOWED */
78377879
default:
78387880
/* Nothing more to do. */
78397881
break;
@@ -25492,6 +25534,14 @@ conversion to an rvalue is forced externally.
2549225534
} else if (!is_initialized(cap) && !is_immediate_class_type(tp)) {
2549325535
do_constexpr_fail(result);
2549425536
info_with_pos(ec_object_not_initialized, &expr->position, ips);
25537+
#if GNU_VECTOR_TYPES_ALLOWED
25538+
} else if (type_is(tp, tk_vector) &&
25539+
!vector_elements_are_initialized(ips, tp, cap)) {
25540+
/* A whole vector is read, but some of its elements are not
25541+
initialized. */
25542+
do_constexpr_fail(result);
25543+
info_with_pos(ec_object_not_initialized, &expr->position, ips);
25544+
#endif /* GNU_VECTOR_TYPES_ALLOWED */
2549525545
} else if (is_variant_path(cap) &&
2549625546
!check_variant_path(ips, cap, &expr->position)) {
2549725547
/* An attempt to dereference an inactive variant path. */
@@ -33158,6 +33208,16 @@ the value representation of the integer value.
3315833208
&expr->position, ips);
3315933209
} /* switch */
3316033210
done:
33211+
#if GNU_VECTOR_TYPES_ALLOWED
33212+
if (pop_when_done && result && type_is(tp, tk_vector) &&
33213+
!is_glvalue_node(expr)) {
33214+
/* The whole vector value has been stored, and its elements can be
33215+
accessed individually (e.g., by subscripting an lvalue for it), so
33216+
mark each of them initialized. */
33217+
mark_whole_subobject_initialized(ips, result_storage, tp,
33218+
complete_object);
33219+
} /* if */
33220+
#endif /* GNU_VECTOR_TYPES_ALLOWED */
3316133221
end_work_visit(ips, result, pop_when_done);
3316233222
#undef SET_result_val_from_operand_address
3316333223
#undef CHECK_int_range
Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
[GH #90]
22
GNU and Clang C++ modes: lifetime extension through a member of a temporary
33

4-
When emulating GCC 9 or later or Clang 4 or later, selecting a member of a
5-
class prvalue now produces an xvalue (Core issue 616), as it already did in
6-
standard C++14 and later modes. Binding a reference to the member now
7-
extends the lifetime of the whole temporary. For example, with
8-
--g++ --gnu_version=150000:
4+
When emulating GCC 9 or later or Clang 4 or later (in C++11 and later
5+
modes), selecting a member of a class prvalue now produces an xvalue (Core
6+
issue 616), as it already did in standard C++14 and later modes. Binding a
7+
reference to the member now extends the lifetime of the whole temporary.
8+
For example, with --g++ --gnu_version=150000:
99

1010
struct A { int b; ~A(); };
1111
const int &r = A().b; // A() was previously destroyed here.
1212

13+
Returning a pointer into a member of a class prvalue is now diagnosed also
14+
when the class is trivially destructible. For example, with --c++20:
15+
16+
struct T { int b; int arr[2]; };
17+
T make();
18+
const int *f() { return &make().arr[1]; } // Warning.
19+
1320
Constant evaluation also no longer treats every member of a class prvalue
1421
as initialized when one is selected with "." or ".*". Since C++20, a
1522
constexpr constructor can leave members uninitialized, and reading such a
@@ -18,3 +25,16 @@ example, with --c++20:
1825

1926
struct W { int n; constexpr W() {} };
2027
static_assert(W().n == 0); // Error: n is uninitialized.
28+
29+
Constant evaluation now also marks each element of a GNU vector as
30+
initialized when a whole vector value is stored (e.g., by a mem-initializer),
31+
and copies the state of each element when an object containing a vector is
32+
copied. Subscripting such a vector could previously give a spurious "access
33+
to uninitialized object" error. Conversely, reading or copying a whole
34+
vector subobject now requires each of its elements to be initialized. For
35+
example, with --g++ --c++20:
36+
37+
typedef int V4 __attribute__((vector_size(16)));
38+
struct Y { V4 v; constexpr Y(V4 a) : v(a) {} };
39+
constexpr int f() { V4 a = {1, 2, 3, 4}; Y y(a); return y.v[3]; }
40+
static_assert(f() == 4, ""); // Previously rejected.

‎tests/expectations/edg_x86_64/imported.log‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6600,7 +6600,6 @@ gnu/cpp/cpp0x/constexpr-typeid/test.mft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
66006600
gnu/cpp/cpp0x/conv-tmpl1.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:FAIL:
66016601
gnu/cpp/cpp0x/conv-tmpl6.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:FAIL:
66026602
gnu/cpp/cpp0x/decltype41/test.mft.cpp:fp:-DTEST_NUMBER=1 --c++11:FAIL:
6603-
gnu/cpp/cpp0x/decltype72.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:FAIL:
66046603
gnu/cpp/cpp0x/decltype80.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
66056604
gnu/cpp/cpp0x/decltype83.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:ABORT:
66066605
gnu/cpp/cpp0x/decltype83a.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:ABORT:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fe_only -DTEST_NUMBER=4 --c++11 --g++ --gnu_version=90000 Test_name.c
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fe_only -DTEST_NUMBER=5 --c++11 --clang --clang_version=40000 Test_name.c

‎tests/tests/cwg/cwg616.sft.cpp‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//type:fp
2-
//options_all:--c++14
3-
//options::--g++ --gnu_version=150000:--clang --clang_version=190100
2+
//options:--c++14:--c++14 --g++ --gnu_version=150000:--c++14 --clang --clang_version=190100:--c++11 --g++ --gnu_version=90000:--c++11 --clang --clang_version=40000
43
template <class T> struct is_xvalue { static const bool value = false; };
54
template <class T> struct is_xvalue<T &&> { static const bool value = true; };
65
struct A { int b; };

0 commit comments

Comments
 (0)