[clang] ab70ac6 - [concepts] Push a CurContext before substituting into out-of-line constraints for comparison (#79985)

via cfe-commits cfe-commits at lists.llvm.org
Tue Jan 30 20:18:00 PST 2024


Author: Younan Zhang
Date: 2024-01-31T12:17:41+08:00
New Revision: ab70ac605e784c630122b27c5971fde68e80bd1b

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

LOG: [concepts] Push a CurContext before substituting into out-of-line constraints for comparison (#79985)

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/AST/DeclTemplate.cpp
    clang/lib/Sema/SemaConcept.cpp
    clang/test/SemaTemplate/concepts-out-of-line-def.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 323157c4db1f1..7b7a5b937a61e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -168,6 +168,9 @@ Bug Fixes to C++ Support
   parameter where we did an incorrect specialization of the initialization of
   the default parameter.
   Fixes (`#68490 <https://github.com/llvm/llvm-project/issues/68490>`_)
+- Addressed an issue where constraints involving injected class types are perceived
+  distinct from its specialization types.
+  (`#56482 <https://github.com/llvm/llvm-project/issues/56482>`_)
 - Fixed a bug where variables referenced by requires-clauses inside
   nested generic lambdas were not properly injected into the constraint scope.
   (`#73418 <https://github.com/llvm/llvm-project/issues/73418>`_)

diff  --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 7d7556e670f95..946a34ea8830e 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -1583,6 +1583,10 @@ void TemplateParamObjectDecl::printAsInit(llvm::raw_ostream &OS,
 
 TemplateParameterList *clang::getReplacedTemplateParameterList(Decl *D) {
   switch (D->getKind()) {
+  case Decl::Kind::CXXRecord:
+    return cast<CXXRecordDecl>(D)
+        ->getDescribedTemplate()
+        ->getTemplateParameters();
   case Decl::Kind::ClassTemplate:
     return cast<ClassTemplateDecl>(D)->getTemplateParameters();
   case Decl::Kind::ClassTemplateSpecialization: {

diff  --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 19a460f411757..5028879eda22f 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -807,8 +807,20 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction(
       ScopeForParameters.InstantiatedLocal(PVD, PVD);
 
   std::optional<Sema::CXXThisScopeRAII> ThisScope;
-  if (auto *RD = dyn_cast<CXXRecordDecl>(DeclInfo.getDeclContext()))
+
+  // See TreeTransform::RebuildTemplateSpecializationType. A context scope is
+  // essential for having an injected class as the canonical type for a template
+  // specialization type at the rebuilding stage. This guarantees that, for
+  // out-of-line definitions, injected class name types and their equivalent
+  // template specializations can be profiled to the same value, which makes it
+  // possible that e.g. constraints involving C<Class<T>> and C<Class> are
+  // perceived identical.
+  std::optional<Sema::ContextRAII> ContextScope;
+  if (auto *RD = dyn_cast<CXXRecordDecl>(DeclInfo.getDeclContext())) {
     ThisScope.emplace(S, const_cast<CXXRecordDecl *>(RD), Qualifiers());
+    ContextScope.emplace(S, const_cast<DeclContext *>(cast<DeclContext>(RD)),
+                         /*NewThisContext=*/false);
+  }
   ExprResult SubstConstr = S.SubstConstraintExprWithoutSatisfaction(
       const_cast<clang::Expr *>(ConstrExpr), MLTAL);
   if (SFINAE.hasErrorOccurred() || !SubstConstr.isUsable())

diff  --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 7323ad8d9ef2c..b6fea2e0b4b31 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -537,6 +537,29 @@ template <class T>
 void X<T>::bar(decltype(requires { requires is_not_same_v<T, int>; })) {}
 } // namespace GH74314
 
+namespace GH56482 {
+template <typename SlotMap>
+concept slot_map_has_reserve = true;
+
+template <typename T> struct Slot_map {
+  constexpr void reserve() const noexcept
+    requires slot_map_has_reserve<Slot_map>;
+
+  constexpr void reserve(int) const noexcept
+    requires slot_map_has_reserve<Slot_map<T>>;
+};
+
+template <typename T>
+constexpr void Slot_map<T>::reserve() const noexcept
+  requires slot_map_has_reserve<Slot_map<T>>
+{}
+
+template <typename T>
+constexpr void Slot_map<T>::reserve(int) const noexcept
+  requires slot_map_has_reserve<Slot_map>
+{}
+} // namespace GH56482
+
 namespace GH74447 {
 template <typename T> struct S {
   template <typename... U, int V>


        


More information about the cfe-commits mailing list