Author: Grigory Pastukhov
Date: 2025-05-16T15:47:53-03:00
New Revision: 48587f30d63689816f3d5a1d199dba42ff332247

URL: 
https://github.com/llvm/llvm-project/commit/48587f30d63689816f3d5a1d199dba42ff332247
DIFF: 
https://github.com/llvm/llvm-project/commit/48587f30d63689816f3d5a1d199dba42ff332247.diff

LOG: [clang] Add new warning: not eliding copy on return (missed NRVO) (#139973)

Added: 
    clang/test/SemaCXX/warn-nrvo.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaDecl.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0c12091a90add..537f29521fb7f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -313,6 +313,8 @@ New Compiler Flags
 
 - New option ``-ftime-report-json`` added which outputs the same timing data 
as ``-ftime-report`` but formatted as JSON.
 
+- New option ``-Wnrvo`` added and disabled by default to warn about missed 
NRVO opportunites.
+
 Deprecated Compiler Flags
 -------------------------
 

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f0bd5a1174020..d78a757c72e4a 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12445,6 +12445,10 @@ def warn_zero_as_null_pointer_constant : Warning<
   "zero as null pointer constant">,
   InGroup<DiagGroup<"zero-as-null-pointer-constant">>, DefaultIgnore;
 
+def warn_not_eliding_copy_on_return : Warning<
+  "not eliding copy on return">, 
+  InGroup<DiagGroup<"nrvo">>, DefaultIgnore;
+
 def err_nullability_cs_multilevel : Error<
   "nullability keyword %0 cannot be applied to multi-level pointer type %1">;
 def note_nullability_type_specifier : Note<

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index a7d59ec232b64..6dae243b520f0 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16093,8 +16093,11 @@ void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo 
*Scope) {
 
   for (unsigned I = 0, E = Scope->Returns.size(); I != E; ++I) {
     if (const VarDecl *NRVOCandidate = Returns[I]->getNRVOCandidate()) {
-      if (!NRVOCandidate->isNRVOVariable())
+      if (!NRVOCandidate->isNRVOVariable()) {
+        Diag(Returns[I]->getRetValue()->getExprLoc(),
+             diag::warn_not_eliding_copy_on_return);
         Returns[I]->setNRVOCandidate(nullptr);
+      }
     }
   }
 }

diff  --git a/clang/test/SemaCXX/warn-nrvo.cpp 
b/clang/test/SemaCXX/warn-nrvo.cpp
new file mode 100644
index 0000000000000..55bbdbd3e6e40
--- /dev/null
+++ b/clang/test/SemaCXX/warn-nrvo.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -fsyntax-only -Wnrvo -Wno-return-mismatch -verify %s
+struct MyClass {
+    int value;
+    int c;
+    MyClass(int v) : value(v), c(0) {}
+    MyClass(const MyClass& other) : value(other.value) { c++; }
+};
+
+MyClass create_object(bool condition) {
+    MyClass obj1(1);
+    MyClass obj2(2);
+    if (condition) {
+        return obj1; // expected-warning{{not eliding copy on return}}
+    }
+    return obj2; // expected-warning{{not eliding copy on return}}
+}
+
+MyClass create_object2(){
+    MyClass obj(1);
+    return obj; // no warning
+}
+
+template<typename T>
+T create_object3(){
+    T obj(1);
+    return obj; // no warning
+}
+
+// Known issue: if a function template uses a 
+// deduced return type (i.e. auto or decltype(auto)), 
+// then NRVO is not applied for any instantiation of 
+// that function template 
+// (see https://github.com/llvm/llvm-project/issues/95280).
+template<typename T>
+auto create_object4(){
+    T obj(1);
+    return obj; // expected-warning{{not eliding copy on return}}
+}
+
+template<bool F>
+MyClass create_object5(){
+    MyClass obj1(1);
+    if constexpr (F){
+        MyClass obj2(2);
+        return obj2; // no warning
+    }
+  // Missed NRVO optimization by clang
+  return obj1; // expected-warning{{not eliding copy on return}}
+}
+
+constexpr bool Flag = false;
+
+MyClass create_object6(){
+  MyClass obj1(1);
+  if constexpr (Flag){
+    MyClass obj2(2);
+    return obj2; // expected-warning{{not eliding copy on return}}
+  }
+  return obj1; // no warning
+}
+
+void create_object7(){
+    if constexpr (Flag){
+        MyClass obj1(1);
+        return obj1; // no warning
+    }
+}
+
+void init_templates(){
+    create_object3<MyClass>(); // no warning
+    create_object4<MyClass>(); // expected-note {{in instantiation of function 
template specialization 'create_object4<MyClass>' requested here}}
+    create_object5<false>(); // expected-note {{in instantiation of function 
template specialization 'create_object5<false>' requested here}}
+}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to