ilya-biryukov updated this revision to Diff 441466.
ilya-biryukov added a comment.

- Update code to match how typedefs behave


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D128921

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/test/Modules/Inputs/merge-concepts/concepts.h
  clang/test/Modules/Inputs/merge-concepts/conflicting.h
  clang/test/Modules/Inputs/merge-concepts/format.h
  clang/test/Modules/Inputs/merge-concepts/modules.map
  clang/test/Modules/Inputs/merge-concepts/same_as.h
  clang/test/Modules/merge-concepts.cpp
  clang/test/Modules/merge-concepts.m

Index: clang/test/Modules/merge-concepts.m
===================================================================
--- /dev/null
+++ clang/test/Modules/merge-concepts.m
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t.dir
+// RUN: mkdir %t.dir
+//
+// RUN: %clang_cc1 -xc++ -std=c++20 -fmodules -fmodule-name=library \
+// RUN:     -emit-module %S/Inputs/merge-concepts/modules.map \
+// RUN:     -o %t.dir/module.pcm
+//
+// Note that this file merely checks the module compiles. The contents of this
+// file are never read by the compiler.
Index: clang/test/Modules/merge-concepts.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/merge-concepts.cpp
@@ -0,0 +1,22 @@
+// RUN: rm -rf %t.dir
+// RUN: mkdir %t.dir
+//
+// RUN: %clang_cc1 -xc++ -std=c++20 -fmodules -fmodule-name=library \
+// RUN:     -emit-module %S/Inputs/merge-concepts/modules.map \
+// RUN:     -o %t.dir/module.pcm
+//
+//
+// RUN: %clang_cc1 -xc++ -std=c++20 -fmodules -fmodule-file=%t.dir/module.pcm  \
+// RUN:     -fmodule-map-file=%S/Inputs/merge-concepts/modules.map \
+// RUN:     -I%S/Inputs/merge-concepts \
+// RUN:     -fsyntax-only -verify %s
+
+#include "concepts.h"
+#include "conflicting.h"
+#include "format.h"
+
+template <class T> void foo()
+  requires same_as<T, T>
+{}
+ConflictingConcept auto x = 10; // expected-error {{reference to 'ConflictingConcept' is ambiguous}}
+                                // expected-note@* 2 {{candidate}}
Index: clang/test/Modules/Inputs/merge-concepts/same_as.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/merge-concepts/same_as.h
@@ -0,0 +1,7 @@
+#ifndef SAME_AS_H
+#define SAME_AS_H
+
+template <class T, class U>
+concept same_as = __is_same(T, U);
+
+#endif // SAME_AS_H
Index: clang/test/Modules/Inputs/merge-concepts/modules.map
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/merge-concepts/modules.map
@@ -0,0 +1,15 @@
+module "library" {
+	export *
+	module "concepts" {
+		export *
+		header "concepts.h"
+	}
+	module "format" {
+		export *
+		header "format.h"
+	}
+	module "conflicting" {
+		export *
+		header "conflicting.h"
+	}
+}
Index: clang/test/Modules/Inputs/merge-concepts/format.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/merge-concepts/format.h
@@ -0,0 +1,11 @@
+#ifndef FORMAT_H
+#define FORMAT_H
+
+#include "concepts.h"
+#include "same_as.h"
+
+template <class T> void foo()
+  requires same_as<T, int>
+{}
+
+#endif // FORMAT_H
Index: clang/test/Modules/Inputs/merge-concepts/conflicting.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/merge-concepts/conflicting.h
@@ -0,0 +1,7 @@
+#ifndef CONFLICTING_H
+#define CONFLICTING_H
+
+template <class T, class U = int>
+concept ConflictingConcept = true;
+
+#endif // CONFLICTING_H
Index: clang/test/Modules/Inputs/merge-concepts/concepts.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/merge-concepts/concepts.h
@@ -0,0 +1,9 @@
+#ifndef SAMEAS_CONCEPTS_H_
+#define SAMEAS_CONCEPTS_H_
+
+#include "same_as.h"
+
+template <class T>
+concept ConflictingConcept = true;
+
+#endif // SAMEAS_CONCEPTS_H
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -8655,23 +8655,53 @@
   // Check for conflicting previous declaration.
   DeclarationNameInfo NameInfo(NewDecl->getDeclName(), NameLoc);
   LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
-                        ForVisibleRedeclaration);
+                        forRedeclarationInCurContext());
   LookupName(Previous, S);
-
   FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage=*/false,
                        /*AllowInlineNamespace*/false);
-  if (!Previous.empty()) {
-    auto *Old = Previous.getRepresentativeDecl();
-    Diag(NameLoc, isa<ConceptDecl>(Old) ? diag::err_redefinition :
-         diag::err_redefinition_different_kind) << NewDecl->getDeclName();
-    Diag(Old->getLocation(), diag::note_previous_definition);
-  }
+  bool AddToScope = true;
+  CheckConceptRedefinition(NewDecl, Previous, AddToScope);
 
   ActOnDocumentableDecl(NewDecl);
-  PushOnScopeChains(NewDecl, S);
+  if (AddToScope)
+    PushOnScopeChains(NewDecl, S);
   return NewDecl;
 }
 
+void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
+                                    LookupResult &Previous, bool &AddToScope) {
+  AddToScope = true;
+  if (Previous.empty())
+    return;
+  // Check if there is a concept declaration we can merge with.
+  auto *PrevDef =
+      Previous.isSingleResult() ? Previous.getAsSingle<ConceptDecl>() : nullptr;
+  if (PrevDef && !hasVisibleDefinition(PrevDef) &&
+      Context.isSameEntity(NewDecl, PrevDef)) {
+    Context.setPrimaryMergedDecl(NewDecl, PrevDef);
+    makeMergedDefinitionVisible(PrevDef);
+    AddToScope = false;
+    return;
+  }
+  // Filter out non-visible declaration to avoid spurious redefinition errors.
+  auto F = Previous.makeFilter();
+  while (F.hasNext()) {
+    if (!isVisible(F.next())) {
+      F.erase();
+    }
+  }
+  F.done();
+  // We report redefinition if the lookup is not empty after filters.
+  if (Previous.empty())
+    return;
+  auto *Old = Previous.getRepresentativeDecl();
+  Diag(NewDecl->getLocation(), isa<ConceptDecl>(Old)
+                                   ? diag::err_redefinition
+                                   : diag::err_redefinition_different_kind)
+      << NewDecl->getDeclName();
+  Diag(Old->getLocation(), diag::note_previous_definition);
+}
+
 /// \brief Strips various properties off an implicit instantiation
 /// that has just been explicitly specialized.
 static void StripImplicitInstantiation(NamedDecl *D) {
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -6512,6 +6512,7 @@
   // and patterns match.
   if (const auto *TemplateX = dyn_cast<TemplateDecl>(X)) {
     const auto *TemplateY = cast<TemplateDecl>(Y);
+    // FIXME: for C++20 concepts, check their requirements are the same.
     return isSameEntity(TemplateX->getTemplatedDecl(),
                         TemplateY->getTemplatedDecl()) &&
            isSameTemplateParameterList(TemplateX->getTemplateParameters(),
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -8180,6 +8180,9 @@
       Scope *S, MultiTemplateParamsArg TemplateParameterLists,
       IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr);
 
+  void CheckConceptRedefinition(ConceptDecl *NewDecl, LookupResult &Previous,
+                                bool &AddToScope);
+
   RequiresExprBodyDecl *
   ActOnStartRequiresExpr(SourceLocation RequiresKWLoc,
                          ArrayRef<ParmVarDecl *> LocalParameters,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to