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
34 changes: 28 additions & 6 deletions src/overload.c
Original file line number Diff line number Diff line change
Expand Up @@ -25425,10 +25425,16 @@ non-const to the indicated (rvalue) operand.
} /* microsoft_can_bind_ref_to_rvalue */


static void check_for_returning_reference_to_local_entity(an_operand *operand)
static void check_for_returning_reference_to_local_entity(
an_operand *operand,
a_boolean similar_lvalue_source)
/*
operand is the entity being bound to a reference in a return statement.
Issue a warning if it is a local entity.
Issue a warning if it is a local entity. Binding the returned reference to
a temporary is an error in C++26 (P2748). similar_lvalue_source is TRUE if
the original initializer was an lvalue of a type similar to the referenced
type; the reference should then bind to it directly (Core issue 2352), so
a temporary found here only gets the warning.
*/
{
a_boolean is_temp;
Expand All @@ -25439,9 +25445,18 @@ Issue a warning if it is a local entity.
/* The expression is a glvalue or class prvalue (object) for a local
entity. Use a different message for temporaries and local
variables. */
expr_pos_warning(is_temp ? ec_return_ref_init_requires_temp :
ec_returning_ref_to_local_variable,
&operand->position);
if (!is_temp) {
expr_pos_warning(ec_returning_ref_to_local_variable,
&operand->position);
} else if (cpp26_mode && !similar_lvalue_source &&
!gpp_version_is(<140000) && !clangcpp_version_is(<190000)) {
/* GCC 14 and Clang 19 implement P2748. Earlier versions only issue
a warning. */
expr_pos_error(ec_return_ref_init_requires_temp, &operand->position);
} else {
expr_pos_warning(ec_return_ref_init_requires_temp,
&operand->position);
} /* if */
} /* if */
} /* if */
} /* check_for_returning_reference_to_local_entity */
Expand Down Expand Up @@ -25614,6 +25629,7 @@ the conversion.
a_boolean ref_to_const = FALSE;
a_boolean ref_to_const_volatile = FALSE;
a_boolean operand_was_rvalue, operand_is_function_lvalue;
a_boolean similar_lvalue_source;
a_boolean warn = FALSE, template_case = FALSE;
a_boolean initializing_variable =
(conv_context & CCO_INITIALIZING_VARIABLE) != 0;
Expand Down Expand Up @@ -25711,6 +25727,11 @@ the conversion.
} /* if */
base_dest_type = type_pointed_to(dest_type);
operand_was_rvalue = is_an_rvalue(source_operand);
/* An lvalue whose type is similar to the referenced type, e.g., an "int **"
lvalue for a "const int *const *const &". The reference binds directly
to it (Core issue 2352). */
similar_lvalue_source = !operand_was_rvalue &&
types_are_similar(orig_source_type, base_dest_type);
operand_is_function_lvalue = is_a_function_designator(source_operand);
adj_base_dest_type = base_dest_type;
if (bitwise_assignment_param) {
Expand Down Expand Up @@ -26316,7 +26337,8 @@ the conversion.
} else if ((conv_context & CCO_INITIALIZING_RETURN_VALUE) &&
!template_case) {
/* Check for returning a reference to a local entity. */
check_for_returning_reference_to_local_entity(source_operand);
check_for_returning_reference_to_local_entity(source_operand,
similar_lvalue_source);
} /* if */
if (!leave_as_object) {
/* Final step: add the reference-to to turn the glvalue or class prvalue
Expand Down
11 changes: 11 additions & 0 deletions src/pending_changes/gh-106-return-ref-to-temporary.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[GH #106]
C++26: returning a reference bound to a temporary is not allowed

A return statement that binds the returned reference to a temporary is not
allowed in C++26 (P2748). The front end only issued a warning. It is now an
error in C++26 (still a warning when emulating GCC versions before 14 or
Clang versions before 19, which do the same). For example, with --c++26:

const int& f() { return 1; } // Now an error.

Returning a reference to a local variable is still only a warning.
1 change: 0 additions & 1 deletion tests/expectations/edg_x86_64/imported.log
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,6 @@ clang/cpp/CXX/special/class.ctor/p1.sft.cpp:fn:-DTEST_NUMBER=1:FAIL:
clang/cpp/CXX/special/class.temporary/p1.sft.cpp:fn:-DTEST_NUMBER=1 --c++11:FAIL:
clang/cpp/CXX/special/class.temporary/p6.sft.cpp:fp:-DTEST_NUMBER=1 --c++17:FAIL:
clang/cpp/CXX/special/class.temporary/p6.sft.cpp:fp:-DTEST_NUMBER=2 --c++23:FAIL:
clang/cpp/CXX/stmt.stmt/stmt.return/p6.sft.cpp:fn:-DTEST_NUMBER=1 --c++26:FAIL:
clang/cpp/CXX/stmt.stmt/stmt.select/stmt.if/p2.sft.cpp:fn:-DTEST_NUMBER=2 --c++17 -DUNDEFINED:FAIL:
clang/cpp/CXX/stmt.stmt/stmt.select/stmt.switch/p4.sft.cpp:fn:-DTEST_NUMBER=1:FAIL:
clang/cpp/CXX/temp/temp.constr/temp.constr.order/non-template-functions.sft.cpp:fp:-DTEST_NUMBER=1 --c++20:FAIL:
Expand Down
18 changes: 18 additions & 0 deletions tests/tests/changes/.GH106.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
fe_only -DTEST_NUMBER=1 --c++26 Test_name.c
"Test_name.c", line 11: error: returning reference to local temporary
const int& f1() { return 1; } // Temporary: diagnosed.
^

"Test_name.c", line 12: error: returning reference to local temporary
const int& f2(long l) { return l; } // Temporary from a conversion.
^

"Test_name.c", line 14: error: returning reference to local temporary
int&& f4() { return 1; } // Rvalue reference to a temporary.
^

"Test_name.c", line 15: warning: returning reference to local variable
const int& f5() { int i = 0; return i; } // Local variable: only a warning.
^

3 errors detected in the compilation of "Test_name.c".
26 changes: 26 additions & 0 deletions tests/tests/changes/.GH106.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
fe_only -DTEST_NUMBER=2 --c++26 --gnu_version 140000 Test_name.c
"Test_name.c", line 11: error: returning reference to local temporary
const int& f1() { return 1; } // Temporary: diagnosed.
^

"Test_name.c", line 12: error: returning reference to local temporary
const int& f2(long l) { return l; } // Temporary from a conversion.
^

"Test_name.c", line 13: error: returning reference to local temporary
const int& f3() { return S().x; } // Member of a temporary.
^

"Test_name.c", line 14: error: returning reference to local temporary
int&& f4() { return 1; } // Rvalue reference to a temporary.
^

"Test_name.c", line 15: warning: returning reference to local variable
const int& f5() { int i = 0; return i; } // Local variable: only a warning.
^

"Test_name.c", line 20: warning: returning reference to local temporary
const int *const *const &f6() { return pp; }
^

4 errors detected in the compilation of "Test_name.c".
26 changes: 26 additions & 0 deletions tests/tests/changes/.GH106.rto/default.3.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
fe_only -DTEST_NUMBER=3 --c++26 --clang_version 190000 Test_name.c
"Test_name.c", line 11: error: returning reference to local temporary
const int& f1() { return 1; } // Temporary: diagnosed.
^

"Test_name.c", line 12: error: returning reference to local temporary
const int& f2(long l) { return l; } // Temporary from a conversion.
^

"Test_name.c", line 13: error: returning reference to local temporary
const int& f3() { return S().x; } // Member of a temporary.
^

"Test_name.c", line 14: error: returning reference to local temporary
int&& f4() { return 1; } // Rvalue reference to a temporary.
^

"Test_name.c", line 15: warning: returning reference to local variable
const int& f5() { int i = 0; return i; } // Local variable: only a warning.
^

"Test_name.c", line 20: warning: returning reference to local temporary
const int *const *const &f6() { return pp; }
^

4 errors detected in the compilation of "Test_name.c".
17 changes: 17 additions & 0 deletions tests/tests/changes/.GH106_a.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
fe_only -DTEST_NUMBER=1 --c++23 Test_name.c
"Test_name.c", line 10: warning: returning reference to local temporary
const int& f1() { return 1; } // Temporary: diagnosed.
^

"Test_name.c", line 11: warning: returning reference to local temporary
const int& f2(long l) { return l; } // Temporary from a conversion.
^

"Test_name.c", line 13: warning: returning reference to local temporary
int&& f4() { return 1; } // Rvalue reference to a temporary.
^

"Test_name.c", line 14: warning: returning reference to local variable
const int& f5() { int i = 0; return i; } // Local variable: only a warning.
^

25 changes: 25 additions & 0 deletions tests/tests/changes/.GH106_a.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
fe_only -DTEST_NUMBER=2 --c++26 --gnu_version 130000 Test_name.c
"Test_name.c", line 10: warning: returning reference to local temporary
const int& f1() { return 1; } // Temporary: diagnosed.
^

"Test_name.c", line 11: warning: returning reference to local temporary
const int& f2(long l) { return l; } // Temporary from a conversion.
^

"Test_name.c", line 12: warning: returning reference to local temporary
const int& f3() { return S().x; } // Member of a temporary.
^

"Test_name.c", line 13: warning: returning reference to local temporary
int&& f4() { return 1; } // Rvalue reference to a temporary.
^

"Test_name.c", line 14: warning: returning reference to local variable
const int& f5() { int i = 0; return i; } // Local variable: only a warning.
^

"Test_name.c", line 19: warning: returning reference to local temporary
const int *const *const &f6() { return pp; }
^

25 changes: 25 additions & 0 deletions tests/tests/changes/.GH106_a.rto/default.3.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
fe_only -DTEST_NUMBER=3 --c++26 --clang_version 180000 Test_name.c
"Test_name.c", line 10: warning: returning reference to local temporary
const int& f1() { return 1; } // Temporary: diagnosed.
^

"Test_name.c", line 11: warning: returning reference to local temporary
const int& f2(long l) { return l; } // Temporary from a conversion.
^

"Test_name.c", line 12: warning: returning reference to local temporary
const int& f3() { return S().x; } // Member of a temporary.
^

"Test_name.c", line 13: warning: returning reference to local temporary
int&& f4() { return 1; } // Rvalue reference to a temporary.
^

"Test_name.c", line 14: warning: returning reference to local variable
const int& f5() { int i = 0; return i; } // Local variable: only a warning.
^

"Test_name.c", line 19: warning: returning reference to local temporary
const int *const *const &f6() { return pp; }
^

20 changes: 20 additions & 0 deletions tests/tests/changes/GH106.sft.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//type:fn
//options:--c++26:--c++26 --gnu_version 140000:--c++26 --clang_version 190000
//remark:[GH #106] C++26: returning a reference bound to a temporary
//
// P2748 makes a return statement that binds the returned reference to a
// temporary ill-formed in C++26. Returning a reference to a local variable
// is still only a warning.

struct S { int x; };

const int& f1() { return 1; } // Temporary: diagnosed.
const int& f2(long l) { return l; } // Temporary from a conversion.
const int& f3() { return S().x; } // Member of a temporary.
int&& f4() { return 1; } // Rvalue reference to a temporary.
const int& f5() { int i = 0; return i; } // Local variable: only a warning.

// Core issue 2352: the reference binds directly to pp, so this is not
// diagnosed as an error.
int **pp;
const int *const *const &f6() { return pp; }
19 changes: 19 additions & 0 deletions tests/tests/changes/GH106_a.sft.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//type:fp
//options:--c++23:--c++26 --gnu_version 130000:--c++26 --clang_version 180000
//remark:[GH #106] Returning a reference bound to a temporary before C++26
//
// Before C++26, and in C++26 when emulating GCC before 14 or Clang before
// 19, returning a reference bound to a temporary is only a warning.

struct S { int x; };

const int& f1() { return 1; } // Temporary: diagnosed.
const int& f2(long l) { return l; } // Temporary from a conversion.
const int& f3() { return S().x; } // Member of a temporary.
int&& f4() { return 1; } // Rvalue reference to a temporary.
const int& f5() { int i = 0; return i; } // Local variable: only a warning.

// Core issue 2352: the reference binds directly to pp, so this is not
// diagnosed as an error.
int **pp;
const int *const *const &f6() { return pp; }
6 changes: 3 additions & 3 deletions tests/tests/cwg/.p2748R5.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
fe_only -DTEST_NUMBER=1 --c++26 Test_name.c
"Test_name.c", line 4: warning: returning reference to local temporary
"Test_name.c", line 4: error: returning reference to local temporary
return 42; // ill-formed
^

"Test_name.c", line 8: warning: returning reference to local temporary
"Test_name.c", line 8: error: returning reference to local temporary
return x; // ill-formed
^

Expand All @@ -12,4 +12,4 @@ At end of source: error: expected a "}"
auto&& f3() {
^

1 error detected in the compilation of "Test_name.c".
3 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_version 999999 --c++26 Test_name.c
"Test_name.c", line 6: warning: returning reference to local temporary
"Test_name.c", line 6: error: returning reference to local temporary
return 42; // expected-error{{returning reference to local temporary object}}
^

"Test_name.c", line 10: warning: returning reference to local temporary
"Test_name.c", line 10: error: returning reference to local temporary
return x; // expected-error{{returning reference to local temporary object}}
^

2 errors detected in the compilation of "Test_name.c".
Loading