ChuanqiXu created this revision.
ChuanqiXu added a reviewer: ilya-biryukov.
ChuanqiXu added a project: clang.
Herald added a project: All.
ChuanqiXu requested review of this revision.
Herald added a subscriber: cfe-commits.

I found this one when I try to add a C++20 Modules example for D130585 
<https://reviews.llvm.org/D130585>. Then I found there are something to improve:
(1) When the declaration is shadowed by using decls, we could try to find its 
targeted decl. This is fine since we would check Previous.isSingleResult() 
before we process anything.
(2) When we complain about the redefinition, we need to check for the existence 
of global module fragment. GMF is designed to make C++20 Named modules to be 
compatible with headers.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D130614

Files:
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/Modules/merge-concepts-in-GMF.cppm

Index: clang/test/Modules/merge-concepts-in-GMF.cppm
===================================================================
--- /dev/null
+++ clang/test/Modules/merge-concepts-in-GMF.cppm
@@ -0,0 +1,63 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface -I%t %t/A.cppm -o %t/A.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface -I%t %t/B.cppm -o %t/B.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface -fprebuilt-module-path=%t %t/Use.cpp -verify -fsyntax-only
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface -fprebuilt-module-path=%t %t/Use2.cpp -verify -fsyntax-only
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface -fprebuilt-module-path=%t %t/Use3.cpp -verify -fsyntax-only
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface -fprebuilt-module-path=%t %t/Use4.cpp -verify -fsyntax-only
+
+//--- foo.h
+template <class T, class U>
+concept same_as = __is_same(T, U);
+
+//--- A.cppm
+module;
+#include "foo.h"
+export module A;
+export using ::same_as;
+
+//--- B.cppm
+module;
+#include "foo.h"
+export module B;
+export using ::same_as;
+
+//--- Use.cpp
+// expected-no-diagnostics
+import A;
+import B;
+
+template <class T> void foo()
+  requires same_as<T, int>
+{}
+
+//--- Use2.cpp
+// expected-no-diagnostics
+#include "foo.h"
+import A;
+
+template <class T> void foo()
+  requires same_as<T, int>
+{}
+
+//--- Use3.cpp
+// expected-no-diagnostics
+import A;
+#include "foo.h"
+
+template <class T> void foo()
+  requires same_as<T, int>
+{}
+
+//--- Use4.cpp
+// expected-no-diagnostics
+import A;
+import B;
+#include "foo.h"
+
+template <class T> void foo()
+  requires same_as<T, int>
+{}
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -8728,9 +8728,12 @@
   if (Previous.empty())
     return;
 
-  auto *OldConcept = dyn_cast<ConceptDecl>(Previous.getRepresentativeDecl());
+  NamedDecl *Old = Previous.getRepresentativeDecl();
+  if (auto *USD = dyn_cast<UsingShadowDecl>(Old))
+    Old = USD->getTargetDecl();
+
+  auto *OldConcept = dyn_cast<ConceptDecl>(Old);
   if (!OldConcept) {
-    auto *Old = Previous.getRepresentativeDecl();
     Diag(NewDecl->getLocation(), diag::err_redefinition_different_kind)
         << NewDecl->getDeclName();
     notePreviousDefinition(Old, NewDecl->getLocation());
@@ -8746,7 +8749,11 @@
     AddToScope = false;
     return;
   }
-  if (hasReachableDefinition(OldConcept)) {
+  if (hasReachableDefinition(OldConcept) &&
+      // When the old decl lives in the GMF and the new decl is same with the
+      // old one, we should merge them instead of complaining.
+      !(OldConcept->getOwningModule() &&
+        OldConcept->getOwningModule()->isGlobalModule())) {
     Diag(NewDecl->getLocation(), diag::err_redefinition)
         << NewDecl->getDeclName();
     notePreviousDefinition(OldConcept, NewDecl->getLocation());
@@ -8758,7 +8765,7 @@
     //        Other decls (e.g. namespaces) also have this shortcoming.
     return;
   }
-  Context.setPrimaryMergedDecl(NewDecl, OldConcept);
+  Context.setPrimaryMergedDecl(NewDecl, OldConcept->getCanonicalDecl());
 }
 
 /// \brief Strips various properties off an implicit instantiation
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to