[C++20] [Modules] Don't create duplicated deduction guides for duplicated classes
authorChuanqi Xu <yedeng.yd@linux.alibaba.com>
Tue, 28 Mar 2023 09:34:43 +0000 (17:34 +0800)
committerChuanqi Xu <yedeng.yd@linux.alibaba.com>
Tue, 28 Mar 2023 09:51:38 +0000 (17:51 +0800)
Close https://github.com/llvm/llvm-project/issues/56916

Within C++20 modules, we may have multiple same constructors in
multiple same RecordDecls. And it doesn't make sense naturally to create
duplicated deduction guides for the duplicated constructors.

clang/docs/StandardCPlusPlusModules.rst
clang/lib/Sema/SemaTemplate.cpp
clang/test/Modules/pr56916.cppm [new file with mode: 0644]
clang/test/Modules/pr61317.cppm

index ab34ba0..e14bbe4 100644 (file)
@@ -660,26 +660,6 @@ the orders matter here in the case.
 
 This is tracked in: https://github.com/llvm/llvm-project/issues/61465
 
-Ambiguous deduction guide
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Currently, when we call deduction guides in global module fragment,
-we may get incorrect diagnosing message like: `ambiguous deduction`.
-
-So if we're using deduction guide from global module fragment, we probably need to write:
-
-.. code-block:: c++
-
-  std::lock_guard<std::mutex> lk(mutex);
-
-instead of
-
-.. code-block:: c++
-
-  std::lock_guard lk(mutex);
-
-This is tracked in: https://github.com/llvm/llvm-project/issues/56916
-
 Ignored PreferredName Attribute
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
index c3338e4..befc1e7 100644 (file)
@@ -2601,13 +2601,21 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
   // FIXME: Skip constructors for which deduction must necessarily fail (those
   // for which some class template parameter without a default argument never
   // appears in a deduced context).
+  llvm::SmallPtrSet<NamedDecl *, 8> ProcessedCtors;
   bool AddedAny = false;
   for (NamedDecl *D : LookupConstructors(Transform.Primary)) {
     D = D->getUnderlyingDecl();
     if (D->isInvalidDecl() || D->isImplicit())
       continue;
+
     D = cast<NamedDecl>(D->getCanonicalDecl());
 
+    // Within C++20 modules, we may have multiple same constructors in
+    // multiple same RecordDecls. And it doesn't make sense to create
+    // duplicated deduction guides for the duplicated constructors.
+    if (ProcessedCtors.count(D))
+      continue;
+
     auto *FTD = dyn_cast<FunctionTemplateDecl>(D);
     auto *CD =
         dyn_cast_or_null<CXXConstructorDecl>(FTD ? FTD->getTemplatedDecl() : D);
@@ -2622,6 +2630,7 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
         }))
       continue;
 
+    ProcessedCtors.insert(D);
     Transform.transformConstructor(FTD, CD);
     AddedAny = true;
   }
diff --git a/clang/test/Modules/pr56916.cppm b/clang/test/Modules/pr56916.cppm
new file mode 100644 (file)
index 0000000..a8b49f0
--- /dev/null
@@ -0,0 +1,41 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 %t/A.cppm -emit-module-interface -o %t/M-A.pcm
+// RUN: %clang_cc1 -std=c++20 %t/B.cppm -emit-module-interface -o %t/M-B.pcm
+// RUN: %clang_cc1 -std=c++20 %t/M.cppm -emit-module-interface -o %t/M.pcm \
+// RUN:     -fprebuilt-module-path=%t
+// RUN: %clang_cc1 -std=c++20 %t/Use.cpp -fmodule-file=M=%t/M.pcm -fsyntax-only \
+// RUN:     -verify
+
+//--- foo.h
+template <typename T>
+class Templ {
+public:
+    Templ(T a) {}
+};
+
+//--- A.cppm
+module;
+#include "foo.h"
+export module M:A;
+export using ::Templ;
+
+//--- B.cppm
+module;
+#include "foo.h"
+export module M:B;
+
+//--- M.cppm
+export module M;
+export import :A;
+export import :B;
+
+//--- Use.cpp
+// expected-no-diagnostics
+import M;
+
+void func() {
+    Templ t(5);
+}
index 4b9c1a3..4b54d26 100644 (file)
@@ -13,7 +13,7 @@
 #define _FOO
 
 template <typename T> struct Foo {
-  Foo(T) {}
+  Foo(T f) {}
 };
 
 template <typename T> Foo(T&) -> Foo<T>;
@@ -24,6 +24,16 @@ struct Bar {
   void baz() const {}
 };
 
+template <typename T> struct Foo2 {
+  Foo2(T f) {}
+};
+
+struct Bar2 {
+  template <typename T>
+    requires requires { Foo2{T()}; }
+  void baz2() const {}
+};
+
 #endif
 
 //--- A.cppm
@@ -32,6 +42,7 @@ module;
 export module A;
 export using ::Foo;
 export using ::Bar;
+export using ::Bar2;
 
 //--- B.cppm
 module;
@@ -46,4 +57,7 @@ import B;
 void use() {
   Bar _; 
   _.baz<int>();
+
+  Bar2 __; 
+  __.baz2<int>();
 }