Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/cmd_line.c
Original file line number Diff line number Diff line change
Expand Up @@ -4317,7 +4317,9 @@ default mode (e.g., exception handling).
if (!option_kind_used[(int)optk_digit_separators]) {
digit_separators_enabled = TRUE;
} /* if */
if (rvalue_references_enabled && !gpp_mode && !clang_mode) {
if (rvalue_references_enabled &&
!gpp_version_is(<90000) && !clangcpp_version_is(<40000)) {
/* A field selection on a class prvalue is an xvalue (CWG 616). */
selection_from_prvalue_is_xvalue = TRUE;
} /* if */
relaxed_constexpr_enabled = TRUE;
Expand Down
8 changes: 8 additions & 0 deletions src/exprutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -25271,6 +25271,10 @@ is_temp can be NULL if that information is not needed.
clear_expr_or_stmt_traversal_block(&tblock);
tblock.process_expr = examine_expr_for_auto_object;
tblock.follow_addressing_path = TRUE;
/* A prvalue.field xvalue (CWG 616) names a subobject of the class
prvalue, so the class object must be considered as well. */
tblock.follow_class_rvalue_addressing_path =
selection_from_prvalue_is_xvalue;
traverse_expr(expr, &tblock);
is_auto_object = tblock.result;
if (is_temp != NULL) *is_temp = tblock.is_temp;
Expand Down Expand Up @@ -25321,6 +25325,10 @@ underlying entity is a temporary, return *is_temp set to TRUE.
clear_expr_or_stmt_traversal_block(&tblock);
tblock.process_expr = examine_expr_for_auto_object;
tblock.follow_addressing_path = TRUE;
/* A pointer into a prvalue.field xvalue (CWG 616) addresses a
subobject of the class prvalue. */
tblock.follow_class_rvalue_addressing_path =
selection_from_prvalue_is_xvalue;
traverse_expr(expr, &tblock);
is_addr_of_auto = tblock.result;
*is_temp = tblock.is_temp;
Expand Down
16 changes: 8 additions & 8 deletions src/il_walk.c
Original file line number Diff line number Diff line change
Expand Up @@ -3266,10 +3266,10 @@ Tips for proper use of the follow_addressing_path mode:
switch (op) {
case eok_dot_field:
/* x.y: Follow x. */
/* We don't have to test for the prvalue.field case here because its
result is a prvalue and therefore wouldn't get here, unless
follow_class_rvalue_addressing_path is TRUE, in which case
we want to keep going anyway. */
/* We don't have to test for the prvalue.field case here: it gets
here only if follow_class_rvalue_addressing_path is TRUE or if
its result is an xvalue (selection_from_prvalue_is_xvalue,
CWG 616), and in both cases we want to keep going. */
traverse_expr(operand1, tblock);
break;
case eok_points_to_field:
Expand All @@ -3278,10 +3278,10 @@ Tips for proper use of the follow_addressing_path mode:
break;
case eok_pm_field:
/* x.*pm: Follow x. */
/* We don't have to test for the prvalue.*pm case here because its
result is a prvalue and therefore wouldn't get here, unless
follow_class_rvalue_addressing_path is TRUE, in which case
we want to keep going anyway. */
/* We don't have to test for the prvalue.*pm case here: it gets
here only if follow_class_rvalue_addressing_path is TRUE or if
its result is an xvalue (selection_from_prvalue_is_xvalue,
CWG 616), and in both cases we want to keep going. */
traverse_expr(operand1, tblock);
break;
case eok_pm_points_to_field:
Expand Down
29 changes: 21 additions & 8 deletions src/interpret.c
Original file line number Diff line number Diff line change
Expand Up @@ -23649,10 +23649,21 @@ after the constructor body has been interpreted.
p_arg_ptr += 1;
arg_size += 1;
} /* for */
if (dip->variant.constructor.value_initialization) {
/* If this is for value initialization, clear the storage first.
Do not, however, overwrite the first word (which may record the
inheritance hierarchy). */
if (!dip->variant.constructor.value_initialization) {
/* Nothing to do. */
} else if (!type_has_user_provided_default_constructor(class_type)) {
/* Value initialization of a class without a user-provided default
constructor zero-initializes the object before calling the
constructor, which need not initialize every subobject (e.g., a
member of a class whose implicit default constructor calls a
user-provided base class constructor). Mark the subobjects as
initialized, so that reading them is valid. */
init_subobject_to_zero(ips, result_storage, class_type,
complete_object);
} else {
/* Otherwise, the object is not zero-initialized, but clear the
storage anyway. Do not, however, overwrite the first word (which
may record the inheritance hierarchy). */
a_byte_count n_class_bytes;
a_boolean dummy = TRUE;
n_class_bytes = f_value_bytes_for_type(ips, class_type, &dummy);
Expand Down Expand Up @@ -31878,8 +31889,9 @@ the value representation of the integer value.
result_addr = *(a_constexpr_address*)opnd1_value;
} else {
/* The first operand is a class rvalue: Create an address for
it. */
mark_complete_object_initialized(opnd1_value);
it. Do not mark the object as fully initialized: since
C++20, a constexpr constructor can leave members
uninitialized, and reading those must be diagnosed. */
clear_address(&result_addr, opnd1_value);
result_addr.alloc_seq_number = ips->storage_stack.alloc_seq();
} /* if */
Expand Down Expand Up @@ -32003,8 +32015,9 @@ the value representation of the integer value.
result_addr = *(a_constexpr_address*)opnd1_value;
} else {
/* The first operand is a class rvalue: Create an address for
it. */
mark_complete_object_initialized(opnd1_value);
it. Do not mark the object as fully initialized: since
C++20, a constexpr constructor can leave members
uninitialized, and reading those must be diagnosed. */
clear_address(&result_addr, opnd1_value);
result_addr.alloc_seq_number = ips->storage_stack.alloc_seq();
} /* if */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[GH #90]
GNU and Clang C++ modes: lifetime extension through a member of a temporary

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

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

Constant evaluation also no longer treats every member of a class prvalue
as initialized when one is selected with "." or ".*". Since C++20, a
constexpr constructor can leave members uninitialized, and reading such a
member is now diagnosed instead of producing an indeterminate value. For
example, with --c++20:

struct W { int n; constexpr W() {} };
static_assert(W().n == 0); // Error: n is uninitialized.
12 changes: 12 additions & 0 deletions src/pending_changes/gh-90-value-init-zeroed-members.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[GH #90]
Constexpr reads of zero-initialized members after value initialization

Value initialization of a class without a user-provided default constructor
zero-initializes the object before calling the constructor. During
constant evaluation, the zeroed members were not treated as initialized, so
reading one that the constructor does not set was rejected. For example,
with --c++20:

struct A { constexpr A() {} int x; };
struct B : A { int y; };
static_assert(B().x == 0); // Previously rejected.
2 changes: 0 additions & 2 deletions tests/expectations/edg_x86_64/imported.log
Original file line number Diff line number Diff line change
Expand Up @@ -7077,7 +7077,6 @@ gnu/cpp/cpp2a/consteval25.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL:
gnu/cpp/cpp2a/consteval32.sft.cpp:fn:-DTEST_NUMBER=1 --c++20:FAIL:
gnu/cpp/cpp2a/constexpr-99287.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL:
gnu/cpp/cpp2a/constexpr-dynamic13.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL:
gnu/cpp/cpp2a/constexpr-init18.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL:
gnu/cpp/cpp2a/constexpr-inst1.sft.cpp:fn:-DTEST_NUMBER=1 --c++14:FAIL:
gnu/cpp/cpp2a/constexpr-inst2.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/cpp2a/constexpr-new11/test.mft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL:
Expand Down Expand Up @@ -7757,7 +7756,6 @@ gnu/cpp/init/new22.sft.cpp:fn:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/new39.sft.cpp:rp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/new40.sft.cpp:rp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/null1.sft.cpp:fp:-DTEST_NUMBER=1 --c++11:FAIL:
gnu/cpp/init/ref19.sft.cpp:rp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/ref23.sft.cpp:fp:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/reference2.sft.cpp:fn:-DTEST_NUMBER=1:FAIL:
gnu/cpp/init/self1.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
Expand Down
1 change: 1 addition & 0 deletions tests/tests/cwg/.cwg616.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=1 --c++14 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/cwg/.cwg616.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=2 --c++14 --g++ --gnu_version=150000 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/cwg/.cwg616.rto/default.3.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=3 --c++14 --clang --clang_version=190100 Test_name.c
14 changes: 14 additions & 0 deletions tests/tests/cwg/cwg616.sft.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//type:fp
//options_all:--c++14
//options::--g++ --gnu_version=150000:--clang --clang_version=190100
template <class T> struct is_xvalue { static const bool value = false; };
template <class T> struct is_xvalue<T &&> { static const bool value = true; };
struct A { int b; };
// Selecting a member of a class prvalue produces an xvalue.
static_assert(is_xvalue<decltype((A().b))>::value, "");
static_assert(is_xvalue<decltype((A().*&A::b))>::value, "");

//cwg: 616
//title: Definition of "indeterminate value"
//meeting: Bristol 4/13
//edg_status: Passes
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --c++20 Test_name.c
"Test_name.c", line 16: error: expression must have a constant value
static_assert(B().x == 0);
^
"Test_name.c", line 16: note: access to uninitialized object
static_assert(B().x == 0);
^

"Test_name.c", line 27: error: class "P0960R3::A" has no suitable copy constructor
A a1(va);
^
Expand Down Expand Up @@ -144,4 +137,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
D d8 = {vdd}; // expected-error {{no matching constructor for initialization of 'D'}}
^

31 errors detected in the compilation of "Test_name.c".
30 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,6 @@ fe_only -DTEST_NUMBER=3 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
const std::type_info &an2 = typeid(n + 1);
^

"Test_name.c", line 213: error: invalid redeclaration of type name "cwg616::T" (declared at line 212)
using T = decltype((static_cast<S&&>(s).n));
^

"Test_name.c", line 214: error: invalid redeclaration of type name "cwg616::T" (declared at line 213)
using T = decltype((f().n));
^

"Test_name.c", line 215: error: invalid redeclaration of type name "cwg616::T" (declared at line 214)
using T = decltype(S().*&S::n);
^

"Test_name.c", line 246: error: incomplete type "int []" is not allowed
sizeof(x);
^
Expand Down Expand Up @@ -635,4 +623,4 @@ At end of source: error: expected a "}"
constexpr int c = true || f();
^

107 errors detected in the compilation of "Test_name.c".
104 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,6 @@ fe_only -DTEST_NUMBER=4 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
const std::type_info &an2 = typeid(n + 1);
^

"Test_name.c", line 213: error: invalid redeclaration of type name "cwg616::T" (declared at line 212)
using T = decltype((static_cast<S&&>(s).n));
^

"Test_name.c", line 214: error: invalid redeclaration of type name "cwg616::T" (declared at line 213)
using T = decltype((f().n));
^

"Test_name.c", line 215: error: invalid redeclaration of type name "cwg616::T" (declared at line 214)
using T = decltype(S().*&S::n);
^

"Test_name.c", line 246: error: incomplete type "int []" is not allowed
sizeof(x);
^
Expand Down Expand Up @@ -628,4 +616,4 @@ At end of source: error: expected a "}"
constexpr int c = true || f();
^

107 errors detected in the compilation of "Test_name.c".
104 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,6 @@ fe_only -DTEST_NUMBER=5 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
const std::type_info &an2 = typeid(n + 1);
^

"Test_name.c", line 213: error: invalid redeclaration of type name "cwg616::T" (declared at line 212)
using T = decltype((static_cast<S&&>(s).n));
^

"Test_name.c", line 214: error: invalid redeclaration of type name "cwg616::T" (declared at line 213)
using T = decltype((f().n));
^

"Test_name.c", line 215: error: invalid redeclaration of type name "cwg616::T" (declared at line 214)
using T = decltype(S().*&S::n);
^

"Test_name.c", line 246: error: incomplete type "int []" is not allowed
sizeof(x);
^
Expand Down Expand Up @@ -612,4 +600,4 @@ At end of source: error: expected a "}"
constexpr int c = true || f();
^

103 errors detected in the compilation of "Test_name.c".
100 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,6 @@ fe_only -DTEST_NUMBER=6 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
const std::type_info &an2 = typeid(n + 1);
^

"Test_name.c", line 213: error: invalid redeclaration of type name "cwg616::T" (declared at line 212)
using T = decltype((static_cast<S&&>(s).n));
^

"Test_name.c", line 214: error: invalid redeclaration of type name "cwg616::T" (declared at line 213)
using T = decltype((f().n));
^

"Test_name.c", line 215: error: invalid redeclaration of type name "cwg616::T" (declared at line 214)
using T = decltype(S().*&S::n);
^

"Test_name.c", line 246: error: incomplete type "int []" is not allowed
sizeof(x);
^
Expand Down Expand Up @@ -600,4 +588,4 @@ At end of source: error: expected a "}"
constexpr int c = true || f();
^

100 errors detected in the compilation of "Test_name.c".
97 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,6 @@ fe_only -DTEST_NUMBER=7 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
const std::type_info &an2 = typeid(n + 1);
^

"Test_name.c", line 213: error: invalid redeclaration of type name "cwg616::T" (declared at line 212)
using T = decltype((static_cast<S&&>(s).n));
^

"Test_name.c", line 214: error: invalid redeclaration of type name "cwg616::T" (declared at line 213)
using T = decltype((f().n));
^

"Test_name.c", line 215: error: invalid redeclaration of type name "cwg616::T" (declared at line 214)
using T = decltype(S().*&S::n);
^

"Test_name.c", line 246: error: incomplete type "int []" is not allowed
sizeof(x);
^
Expand Down Expand Up @@ -600,4 +588,4 @@ At end of source: error: expected a "}"
constexpr int c = true || f();
^

100 errors detected in the compilation of "Test_name.c".
97 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,6 @@ fe_only -DTEST_NUMBER=3 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
const std::type_info &an2 = typeid(n + 1);
^

"Test_name.c", line 213: error: invalid redeclaration of type name "cwg616::T" (declared at line 212)
using T = decltype((static_cast<S&&>(s).n));
^

"Test_name.c", line 214: error: invalid redeclaration of type name "cwg616::T" (declared at line 213)
using T = decltype((f().n));
^

"Test_name.c", line 215: error: invalid redeclaration of type name "cwg616::T" (declared at line 214)
using T = decltype(S().*&S::n);
^

"Test_name.c", line 246: error: incomplete type "int []" is not allowed
sizeof(x);
^
Expand Down Expand Up @@ -639,4 +627,4 @@ At end of source: error: expected a "}"
constexpr int c = true || f();
^

107 errors detected in the compilation of "Test_name.c".
104 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,6 @@ fe_only -DTEST_NUMBER=4 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
const std::type_info &an2 = typeid(n + 1);
^

"Test_name.c", line 213: error: invalid redeclaration of type name "cwg616::T" (declared at line 212)
using T = decltype((static_cast<S&&>(s).n));
^

"Test_name.c", line 214: error: invalid redeclaration of type name "cwg616::T" (declared at line 213)
using T = decltype((f().n));
^

"Test_name.c", line 215: error: invalid redeclaration of type name "cwg616::T" (declared at line 214)
using T = decltype(S().*&S::n);
^

"Test_name.c", line 246: error: incomplete type "int []" is not allowed
sizeof(x);
^
Expand Down Expand Up @@ -632,4 +620,4 @@ At end of source: error: expected a "}"
constexpr int c = true || f();
^

107 errors detected in the compilation of "Test_name.c".
104 errors detected in the compilation of "Test_name.c".
Loading