rZhBoYao updated this revision to Diff 541151.
rZhBoYao retitled this revision from "[Clang][Sema] Add -Wctad-copy-not-wrap to 
diagnose copy deduction candidate" to "[Clang][Sema] Add -Wctad-selects-copy to 
diagnose copy deduction candidate".
rZhBoYao edited the summary of this revision.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D155475/new/

https://reviews.llvm.org/D155475

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaInit.cpp
  clang/test/SemaTemplate/ctad.cpp

Index: clang/test/SemaTemplate/ctad.cpp
===================================================================
--- clang/test/SemaTemplate/ctad.cpp
+++ clang/test/SemaTemplate/ctad.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++17 -verify %s
+// RUN: %clang_cc1 -std=c++23 -verify %s
 
 namespace pr41427 {
   template <typename T> class A {
@@ -44,3 +44,32 @@
   };
   D z = {Z(), {}};
 }
+
+namespace warn_ctad_copy {
+#pragma clang diagnostic push
+#pragma clang diagnostic warning "-Wctad-selects-copy"
+// like std::revrse_iterator, the motivating example
+template <typename T> struct CTAD {
+  template <typename From>
+    requires(!__is_same(From, T) && __is_convertible_to(From, T))
+  CTAD(const CTAD<From>&) {} // #1
+  CTAD(T) {}
+};
+CTAD(void) -> CTAD<void>; // does not suppress -Wctad-selects-copy
+
+CTAD<int>&   fc1();
+CTAD<double> fc2(),
+             c1 = fc1();         // uses #1
+CTAD c2 = fc2(),                 // OK, uses copy-initialization
+     c3 = CTAD(4.2);             // OK, copy deduction candidate not selected
+CTAD c4{fc2()};                  // test prvalue expression
+// expected-warning@-1{{move-constructing not wrapping a 'CTAD<double>' \
+(aka 'warn_ctad_copy::CTAD<double>'), use copy-list-initialization to suppress this warning}}
+CTAD c5 = CTAD{fc1()};           // test lvalue  expression
+// expected-warning@-1{{copy-constructing not wrapping a 'CTAD<int>' \
+(aka 'warn_ctad_copy::CTAD<int>'), use copy-list-initialization to suppress this warning}}
+auto c6 = CTAD((CTAD<int>&&)c5); // test xvalue  expression
+// expected-warning@-1{{move-constructing not wrapping a 'CTAD<int>' \
+(aka 'warn_ctad_copy::CTAD<int>'), use copy-initialization to suppress this warning}}
+#pragma clang diagnostic pop
+} // namespace warn_ctad_copy
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -19,6 +19,7 @@
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/Designator.h"
 #include "clang/Sema/EnterExpressionEvaluationContext.h"
 #include "clang/Sema/Initialization.h"
@@ -10908,6 +10909,18 @@
        diag::warn_cxx14_compat_class_template_argument_deduction)
       << TSInfo->getTypeLoc().getSourceRange() << 1 << DeducedType;
 
+  // Warn if the copy deduction candidate is selected in direct-initialization.
+  auto DiagnoseCTADCopy = [&] {
+    if (auto IK = Kind.getKind();
+        IK <= InitializationKind::IK_DirectList &&
+        cast<CXXDeductionGuideDecl>(Best->Function)
+                ->getDeductionCandidateKind() == DeductionCandidate::Copy) {
+      Diag(Kind.getLocation(), diag::warn_ctad_selects_copy)
+          << Kind.getRange() << Inits.front()->isLValue() << DeducedType
+          << !ListInit;
+    }
+  };
+
   // Warn if CTAD was used on a type that does not have any user-defined
   // deduction guides.
   if (!FoundDeductionGuide) {
@@ -10915,6 +10928,9 @@
          diag::warn_ctad_maybe_unsupported)
         << TemplateName;
     Diag(Template->getLocation(), diag::note_suppress_ctad_maybe_unsupported);
+    DiagnoseCTADCopy();
+  } else if (!PP.getSourceManager().isInSystemHeader(Template->getLocation())) {
+    DiagnoseCTADCopy();
   }
 
   return DeducedType;
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2488,6 +2488,10 @@
   InGroup<CTADMaybeUnsupported>, DefaultIgnore;
 def note_suppress_ctad_maybe_unsupported : Note<
   "add a deduction guide to suppress this warning">;
+def warn_ctad_selects_copy : Warning<
+  "%select{move|copy}0-constructing not wrapping a %1, "
+  "use copy-%select{list-|}2initialization to suppress this warning">,
+  InGroup<CTADSelectsCopy>, DefaultIgnore;
 
 
 // C++14 deduced return types
Index: clang/include/clang/Basic/DiagnosticGroups.td
===================================================================
--- clang/include/clang/Basic/DiagnosticGroups.td
+++ clang/include/clang/Basic/DiagnosticGroups.td
@@ -1380,6 +1380,10 @@
 def CrossTU : DiagGroup<"ctu">;
 
 def CTADMaybeUnsupported : DiagGroup<"ctad-maybe-unsupported">;
+def CTADSelectsCopy      : DiagGroup<"ctad-selects-copy">;
+def CTADMaybeUnintended  : DiagGroup<"ctad-maybe-unintended", [
+    CTADMaybeUnsupported, CTADSelectsCopy
+  ]>;
 
 def FortifySource : DiagGroup<"fortify-source">;
 
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -421,6 +421,20 @@
 - ``-Wformat`` will no longer suggest a no-op fix-it for fixing scoped enum format
   warnings. Instead, it will suggest casting the enum object to the type specified
   in the format string.
+- Clang now warns when the class template argument deduction deduces the type to be the same as the initializer
+  of a direct-initialization. Turn this on with ``-Wctad-selects-copy``. If the class template is in a system header
+  and a reachable explicit deduction guide is present, the warning is suppressed.
+  (`#63288 <https://github.com/llvm/llvm-project/issues/63288>`_).
+
+  .. code-block:: c++
+
+    auto vec = std::vector{42};
+    auto v = std::vector{vec}; // no warning, user-defined deduction guides exist
+                               // and the template is in a system header
+
+    std::reverse_iterator it1 = v.rbegin();       // no warning, copy-initialization
+    auto it2 = std::reverse_iterator{v.rbegin()}; // warns, the intent might be the next line
+    auto it3 = std::reverse_iterator<decltype(v.rbegin())>(v.rbegin()); // no warning, no CTAD
 
 Bug Fixes in This Version
 -------------------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D155475: [Clang][S... PoYao Chang via Phabricator via cfe-commits

Reply via email to