Skip to content

Commit f101ddc

Browse files
Exempt the is_convertible check from P2748 and diagnose references to members of temporaries. [GH #106]
1 parent eb3d528 commit f101ddc

8 files changed

Lines changed: 77 additions & 13 deletions

File tree

‎src/exprutil.c‎

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25254,13 +25254,14 @@ that identifies an object or a prvalue that is a pointer to an object.
2525425254
} /* examine_expr_for_auto_object */
2525525255

2525625256

25257-
a_boolean is_glvalue_for_auto_object(an_expr_node_ptr expr,
25258-
a_boolean *is_temp)
25257+
static a_boolean glvalue_for_auto_object(an_expr_node_ptr expr,
25258+
a_boolean follow_prvalues,
25259+
a_boolean *is_temp)
2525925260
/*
25260-
Return TRUE if expr is a glvalue whose underlying object is known to
25261-
be an automatic (stack-based) entity. The safe answer is FALSE. If the
25262-
underlying entity is a temporary, return *is_temp set to TRUE.
25263-
is_temp can be NULL if that information is not needed.
25261+
Do the work for is_glvalue_for_auto_object and
25262+
is_glvalue_for_auto_object_or_temp_subobject. If follow_prvalues is TRUE,
25263+
the traversal continues through class prvalues, so that a subobject of a
25264+
temporary (e.g., "S().x") is found.
2526425265
*/
2526525266
{
2526625267
a_boolean is_auto_object = FALSE;
@@ -25271,14 +25272,41 @@ is_temp can be NULL if that information is not needed.
2527125272
clear_expr_or_stmt_traversal_block(&tblock);
2527225273
tblock.process_expr = examine_expr_for_auto_object;
2527325274
tblock.follow_addressing_path = TRUE;
25275+
tblock.follow_class_rvalue_addressing_path = follow_prvalues;
2527425276
traverse_expr(expr, &tblock);
2527525277
is_auto_object = tblock.result;
2527625278
if (is_temp != NULL) *is_temp = tblock.is_temp;
2527725279
} /* if */
2527825280
return is_auto_object;
25281+
} /* glvalue_for_auto_object */
25282+
25283+
25284+
a_boolean is_glvalue_for_auto_object(an_expr_node_ptr expr,
25285+
a_boolean *is_temp)
25286+
/*
25287+
Return TRUE if expr is a glvalue whose underlying object is known to
25288+
be an automatic (stack-based) entity. The safe answer is FALSE. If the
25289+
underlying entity is a temporary, return *is_temp set to TRUE.
25290+
is_temp can be NULL if that information is not needed.
25291+
*/
25292+
{
25293+
return glvalue_for_auto_object(expr, /*follow_prvalues=*/FALSE, is_temp);
2527925294
} /* is_glvalue_for_auto_object */
2528025295

2528125296

25297+
a_boolean is_glvalue_for_auto_object_or_temp_subobject(
25298+
an_expr_node_ptr expr,
25299+
a_boolean *is_temp)
25300+
/*
25301+
Like is_glvalue_for_auto_object, but also return TRUE (with *is_temp set to
25302+
TRUE) if expr is a glvalue for a subobject of a class prvalue temporary,
25303+
e.g., "S().x".
25304+
*/
25305+
{
25306+
return glvalue_for_auto_object(expr, /*follow_prvalues=*/TRUE, is_temp);
25307+
} /* is_glvalue_for_auto_object_or_temp_subobject */
25308+
25309+
2528225310
a_boolean is_prvalue_for_auto_object(an_expr_node_ptr expr,
2528325311
a_boolean *is_temp)
2528425312
/*

‎src/exprutil.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3149,6 +3149,10 @@ extern a_boolean still_an_lvalue(a_type_ptr type_before_cast,
31493149
extern a_boolean is_glvalue_for_auto_object(an_expr_node_ptr expr,
31503150
a_boolean *is_temp);
31513151

3152+
extern a_boolean is_glvalue_for_auto_object_or_temp_subobject(
3153+
an_expr_node_ptr expr,
3154+
a_boolean *is_temp);
3155+
31523156
extern a_boolean is_prvalue_for_auto_object(an_expr_node_ptr expr,
31533157
a_boolean *is_temp);
31543158

‎src/overload.c‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25440,11 +25440,12 @@ a temporary found here only gets the warning.
2544025440
a_boolean is_temp;
2544125441

2544225442
if (is_expression_operand(operand)) {
25443-
if (is_glvalue_for_auto_object(operand->variant.expression, &is_temp) ||
25443+
if (is_glvalue_for_auto_object_or_temp_subobject(
25444+
operand->variant.expression, &is_temp) ||
2544425445
is_prvalue_for_auto_object(operand->variant.expression, &is_temp)) {
2544525446
/* The expression is a glvalue or class prvalue (object) for a local
25446-
entity. Use a different message for temporaries and local
25447-
variables. */
25447+
entity (possibly a subobject of a temporary). Use a different
25448+
message for temporaries and local variables. */
2544825449
if (!is_temp) {
2544925450
expr_pos_warning(ec_returning_ref_to_local_variable,
2545025451
&operand->position);
@@ -26335,8 +26336,12 @@ the conversion.
2633526336
source_operand,
2633626337
(conv_context & CCO_STATIC_LIFETIME) != 0);
2633726338
} else if ((conv_context & CCO_INITIALIZING_RETURN_VALUE) &&
26339+
(conv_context & CCO_TYPE_TRAITS_CHECK) == 0 &&
2633826340
!template_case) {
26339-
/* Check for returning a reference to a local entity. */
26341+
/* Check for returning a reference to a local entity. This is not done
26342+
for the invented function of the is_convertible check: P2748, which
26343+
makes binding a returned reference to a temporary ill-formed in C++26,
26344+
does not apply to it. */
2634026345
check_for_returning_reference_to_local_entity(source_operand,
2634126346
similar_lvalue_source);
2634226347
} /* if */

‎src/pending_changes/gh-106-return-ref-to-temporary.txt‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ allowed in C++26 (P2748). The front end only issued a warning. It is now an
66
error in C++26 (still a warning when emulating GCC versions before 14 or
77
Clang versions before 19, which do the same). For example, with --c++26:
88

9-
const int& f() { return 1; } // Now an error.
9+
struct S { int x; };
10+
const int& f() { return 1; } // Now an error.
11+
const int& g() { return S().x; } // Now an error.
1012

11-
Returning a reference to a local variable is still only a warning.
13+
Returning a reference to a member of a temporary, as in g, was previously not
14+
diagnosed at all in the standard (non-GNU, non-Clang) modes; before C++26 it
15+
now gets the same warning as the other cases. Returning a reference to a
16+
local variable is still only a warning.
17+
18+
As P2748 specifies, this does not apply to the conversion checked by
19+
std::is_convertible (e.g., __is_convertible_to(long, const int&) is still
20+
true).

‎tests/tests/changes/.GH106.rto/default.1.1.txt‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ fe_only -DTEST_NUMBER=1 --c++26 Test_name.c
77
const int& f2(long l) { return l; } // Temporary from a conversion.
88
^
99

10+
"Test_name.c", line 13: error: returning reference to local temporary
11+
const int& f3() { return S().x; } // Member of a temporary.
12+
^
13+
1014
"Test_name.c", line 14: error: returning reference to local temporary
1115
int&& f4() { return 1; } // Rvalue reference to a temporary.
1216
^
@@ -15,4 +19,4 @@ fe_only -DTEST_NUMBER=1 --c++26 Test_name.c
1519
const int& f5() { int i = 0; return i; } // Local variable: only a warning.
1620
^
1721

18-
3 errors detected in the compilation of "Test_name.c".
22+
4 errors detected in the compilation of "Test_name.c".

‎tests/tests/changes/.GH106_a.rto/default.1.1.txt‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ fe_only -DTEST_NUMBER=1 --c++23 Test_name.c
77
const int& f2(long l) { return l; } // Temporary from a conversion.
88
^
99

10+
"Test_name.c", line 12: warning: returning reference to local temporary
11+
const int& f3() { return S().x; } // Member of a temporary.
12+
^
13+
1014
"Test_name.c", line 13: warning: returning reference to local temporary
1115
int&& f4() { return 1; } // Rvalue reference to a temporary.
1216
^

‎tests/tests/changes/GH106.sft.cpp‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,8 @@ const int& f5() { int i = 0; return i; } // Local variable: only a warning.
1818
// diagnosed as an error.
1919
int **pp;
2020
const int *const *const &f6() { return pp; }
21+
22+
// P2748 does not apply to the invented function used for is_convertible.
23+
static_assert(__is_convertible_to(int, const int&), "");
24+
static_assert(__is_convertible_to(long, const int&), "");
25+
static_assert(__is_convertible_to(S, const S&), "");

‎tests/tests/changes/GH106_a.sft.cpp‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,8 @@ const int& f5() { int i = 0; return i; } // Local variable: only a warning.
1717
// diagnosed as an error.
1818
int **pp;
1919
const int *const *const &f6() { return pp; }
20+
21+
// P2748 does not apply to the invented function used for is_convertible.
22+
static_assert(__is_convertible_to(int, const int&), "");
23+
static_assert(__is_convertible_to(long, const int&), "");
24+
static_assert(__is_convertible_to(S, const S&), "");

0 commit comments

Comments
 (0)