Skip to content

Commit 48587f3

Browse files
authored
[clang] Add new warning: not eliding copy on return (missed NRVO) (#139973)
1 parent 4e01a07 commit 48587f3

File tree

4 files changed

+83
-1
lines changed

4 files changed

+83
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ New Compiler Flags
313313

314314
- New option ``-ftime-report-json`` added which outputs the same timing data as ``-ftime-report`` but formatted as JSON.
315315

316+
- New option ``-Wnrvo`` added and disabled by default to warn about missed NRVO opportunites.
317+
316318
Deprecated Compiler Flags
317319
-------------------------
318320

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12445,6 +12445,10 @@ def warn_zero_as_null_pointer_constant : Warning<
1244512445
"zero as null pointer constant">,
1244612446
InGroup<DiagGroup<"zero-as-null-pointer-constant">>, DefaultIgnore;
1244712447

12448+
def warn_not_eliding_copy_on_return : Warning<
12449+
"not eliding copy on return">,
12450+
InGroup<DiagGroup<"nrvo">>, DefaultIgnore;
12451+
1244812452
def err_nullability_cs_multilevel : Error<
1244912453
"nullability keyword %0 cannot be applied to multi-level pointer type %1">;
1245012454
def note_nullability_type_specifier : Note<

clang/lib/Sema/SemaDecl.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16093,8 +16093,11 @@ void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) {
1609316093

1609416094
for (unsigned I = 0, E = Scope->Returns.size(); I != E; ++I) {
1609516095
if (const VarDecl *NRVOCandidate = Returns[I]->getNRVOCandidate()) {
16096-
if (!NRVOCandidate->isNRVOVariable())
16096+
if (!NRVOCandidate->isNRVOVariable()) {
16097+
Diag(Returns[I]->getRetValue()->getExprLoc(),
16098+
diag::warn_not_eliding_copy_on_return);
1609716099
Returns[I]->setNRVOCandidate(nullptr);
16100+
}
1609816101
}
1609916102
}
1610016103
}

clang/test/SemaCXX/warn-nrvo.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %clang_cc1 -fsyntax-only -Wnrvo -Wno-return-mismatch -verify %s
2+
struct MyClass {
3+
int value;
4+
int c;
5+
MyClass(int v) : value(v), c(0) {}
6+
MyClass(const MyClass& other) : value(other.value) { c++; }
7+
};
8+
9+
MyClass create_object(bool condition) {
10+
MyClass obj1(1);
11+
MyClass obj2(2);
12+
if (condition) {
13+
return obj1; // expected-warning{{not eliding copy on return}}
14+
}
15+
return obj2; // expected-warning{{not eliding copy on return}}
16+
}
17+
18+
MyClass create_object2(){
19+
MyClass obj(1);
20+
return obj; // no warning
21+
}
22+
23+
template<typename T>
24+
T create_object3(){
25+
T obj(1);
26+
return obj; // no warning
27+
}
28+
29+
// Known issue: if a function template uses a
30+
// deduced return type (i.e. auto or decltype(auto)),
31+
// then NRVO is not applied for any instantiation of
32+
// that function template
33+
// (see https://github.com/llvm/llvm-project/issues/95280).
34+
template<typename T>
35+
auto create_object4(){
36+
T obj(1);
37+
return obj; // expected-warning{{not eliding copy on return}}
38+
}
39+
40+
template<bool F>
41+
MyClass create_object5(){
42+
MyClass obj1(1);
43+
if constexpr (F){
44+
MyClass obj2(2);
45+
return obj2; // no warning
46+
}
47+
// Missed NRVO optimization by clang
48+
return obj1; // expected-warning{{not eliding copy on return}}
49+
}
50+
51+
constexpr bool Flag = false;
52+
53+
MyClass create_object6(){
54+
MyClass obj1(1);
55+
if constexpr (Flag){
56+
MyClass obj2(2);
57+
return obj2; // expected-warning{{not eliding copy on return}}
58+
}
59+
return obj1; // no warning
60+
}
61+
62+
void create_object7(){
63+
if constexpr (Flag){
64+
MyClass obj1(1);
65+
return obj1; // no warning
66+
}
67+
}
68+
69+
void init_templates(){
70+
create_object3<MyClass>(); // no warning
71+
create_object4<MyClass>(); // expected-note {{in instantiation of function template specialization 'create_object4<MyClass>' requested here}}
72+
create_object5<false>(); // expected-note {{in instantiation of function template specialization 'create_object5<false>' requested here}}
73+
}

0 commit comments

Comments
 (0)