[clang] Revert "Reapply "[Clang][Sema] Always use latest redeclaration of primary template" (#114569)" (PR #115156)

Krystian Stasiowski via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 6 05:37:42 PST 2024


https://github.com/sdkrystian created https://github.com/llvm/llvm-project/pull/115156

This reverts commit b24650e814e55d90acfc40acf045456c98f32b9c.

>From 026f442bd600bd50921bdcfe550b5ff4c376066e Mon Sep 17 00:00:00 2001
From: Krystian Stasiowski <sdkrystian at gmail.com>
Date: Wed, 6 Nov 2024 08:28:50 -0500
Subject: [PATCH] Revert "Reapply "[Clang][Sema] Always use latest
 redeclaration of primary template" (#114569)"

This reverts commit b24650e814e55d90acfc40acf045456c98f32b9c.
---
 clang/include/clang/AST/DeclTemplate.h        | 52 +++++++++--
 clang/lib/AST/ASTImporter.cpp                 |  3 +-
 clang/lib/AST/Decl.cpp                        | 10 +--
 clang/lib/AST/DeclCXX.cpp                     |  4 +-
 clang/lib/AST/DeclTemplate.cpp                | 56 +-----------
 clang/lib/Sema/SemaDecl.cpp                   |  4 +-
 clang/lib/Sema/SemaInit.cpp                   |  2 +-
 clang/lib/Sema/SemaTemplateInstantiate.cpp    | 14 +--
 clang/test/AST/ast-dump-decl.cpp              |  2 +-
 .../Inputs/class-template-spec.cpp            | 47 ----------
 .../ASTMerge/class-template-spec/test.cpp     |  8 --
 .../CXX/temp/temp.spec/temp.expl.spec/p7.cpp  | 87 -------------------
 12 files changed, 67 insertions(+), 222 deletions(-)
 delete mode 100644 clang/test/ASTMerge/class-template-spec/Inputs/class-template-spec.cpp
 delete mode 100644 clang/test/ASTMerge/class-template-spec/test.cpp

diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 0ca3fd48e81cf4..a572e3380f1655 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -857,6 +857,16 @@ class RedeclarableTemplateDecl : public TemplateDecl,
   /// \endcode
   bool isMemberSpecialization() const { return Common.getInt(); }
 
+  /// Determines whether any redeclaration of this template was
+  /// a specialization of a member template.
+  bool hasMemberSpecialization() const {
+    for (const auto *D : redecls()) {
+      if (D->isMemberSpecialization())
+        return true;
+    }
+    return false;
+  }
+
   /// Note that this member template is a specialization.
   void setMemberSpecialization() {
     assert(!isMemberSpecialization() && "already a member specialization");
@@ -1955,7 +1965,13 @@ class ClassTemplateSpecializationDecl : public CXXRecordDecl,
   /// specialization which was specialized by this.
   llvm::PointerUnion<ClassTemplateDecl *,
                      ClassTemplatePartialSpecializationDecl *>
-  getSpecializedTemplateOrPartial() const;
+  getSpecializedTemplateOrPartial() const {
+    if (const auto *PartialSpec =
+            SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
+      return PartialSpec->PartialSpecialization;
+
+    return SpecializedTemplate.get<ClassTemplateDecl*>();
+  }
 
   /// Retrieve the set of template arguments that should be used
   /// to instantiate members of the class template or class template partial
@@ -2192,6 +2208,17 @@ class ClassTemplatePartialSpecializationDecl
     return InstantiatedFromMember.getInt();
   }
 
+  /// Determines whether any redeclaration of this this class template partial
+  /// specialization was a specialization of a member partial specialization.
+  bool hasMemberSpecialization() const {
+    for (const auto *D : redecls()) {
+      if (cast<ClassTemplatePartialSpecializationDecl>(D)
+              ->isMemberSpecialization())
+        return true;
+    }
+    return false;
+  }
+
   /// Note that this member template is a specialization.
   void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
 
@@ -2713,7 +2740,13 @@ class VarTemplateSpecializationDecl : public VarDecl,
   /// Retrieve the variable template or variable template partial
   /// specialization which was specialized by this.
   llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
-  getSpecializedTemplateOrPartial() const;
+  getSpecializedTemplateOrPartial() const {
+    if (const auto *PartialSpec =
+            SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
+      return PartialSpec->PartialSpecialization;
+
+    return SpecializedTemplate.get<VarTemplateDecl *>();
+  }
 
   /// Retrieve the set of template arguments that should be used
   /// to instantiate the initializer of the variable template or variable
@@ -2947,6 +2980,18 @@ class VarTemplatePartialSpecializationDecl
     return InstantiatedFromMember.getInt();
   }
 
+  /// Determines whether any redeclaration of this this variable template
+  /// partial specialization was a specialization of a member partial
+  /// specialization.
+  bool hasMemberSpecialization() const {
+    for (const auto *D : redecls()) {
+      if (cast<VarTemplatePartialSpecializationDecl>(D)
+              ->isMemberSpecialization())
+        return true;
+    }
+    return false;
+  }
+
   /// Note that this member template is a specialization.
   void setMemberSpecialization() { return InstantiatedFromMember.setInt(true); }
 
@@ -3119,9 +3164,6 @@ class VarTemplateDecl : public RedeclarableTemplateDecl {
     return makeSpecIterator(getSpecializations(), true);
   }
 
-  /// Merge \p Prev with our RedeclarableTemplateDecl::Common.
-  void mergePrevDecl(VarTemplateDecl *Prev);
-
   // Implement isa/cast/dyncast support
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) { return K == VarTemplate; }
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 9d0b77566f6747..6e31df691fa104 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -6190,8 +6190,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
 ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
                                           ClassTemplateSpecializationDecl *D) {
   ClassTemplateDecl *ClassTemplate;
-  if (Error Err = importInto(ClassTemplate,
-                             D->getSpecializedTemplate()->getCanonicalDecl()))
+  if (Error Err = importInto(ClassTemplate, D->getSpecializedTemplate()))
     return std::move(Err);
 
   // Import the context of this declaration.
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index cd173d17263792..86913763ef9ff5 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2708,7 +2708,7 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
     if (isTemplateInstantiation(VDTemplSpec->getTemplateSpecializationKind())) {
       auto From = VDTemplSpec->getInstantiatedFrom();
       if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
-        while (!VTD->isMemberSpecialization()) {
+        while (!VTD->hasMemberSpecialization()) {
           if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
             VTD = NewVTD;
           else
@@ -2718,7 +2718,7 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
       }
       if (auto *VTPSD =
               From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
-        while (!VTPSD->isMemberSpecialization()) {
+        while (!VTPSD->hasMemberSpecialization()) {
           if (auto *NewVTPSD = VTPSD->getInstantiatedFromMember())
             VTPSD = NewVTPSD;
           else
@@ -2732,7 +2732,7 @@ VarDecl *VarDecl::getTemplateInstantiationPattern() const {
   // If this is the pattern of a variable template, find where it was
   // instantiated from. FIXME: Is this necessary?
   if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) {
-    while (!VTD->isMemberSpecialization()) {
+    while (!VTD->hasMemberSpecialization()) {
       if (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate())
         VTD = NewVTD;
       else
@@ -4153,7 +4153,7 @@ FunctionDecl::getTemplateInstantiationPattern(bool ForDefinition) const {
   if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
     // If we hit a point where the user provided a specialization of this
     // template, we're done looking.
-    while (!ForDefinition || !Primary->isMemberSpecialization()) {
+    while (!ForDefinition || !Primary->hasMemberSpecialization()) {
       if (auto *NewPrimary = Primary->getInstantiatedFromMemberTemplate())
         Primary = NewPrimary;
       else
@@ -4170,7 +4170,7 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
   if (FunctionTemplateSpecializationInfo *Info
         = TemplateOrSpecialization
             .dyn_cast<FunctionTemplateSpecializationInfo*>()) {
-    return Info->getTemplate()->getMostRecentDecl();
+    return Info->getTemplate();
   }
   return nullptr;
 }
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 1c92fd9e3ff067..db0ea62a2323eb 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2030,7 +2030,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
   if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) {
     auto From = TD->getInstantiatedFrom();
     if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) {
-      while (!CTD->isMemberSpecialization()) {
+      while (!CTD->hasMemberSpecialization()) {
         if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
           CTD = NewCTD;
         else
@@ -2040,7 +2040,7 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
     }
     if (auto *CTPSD =
             From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
-      while (!CTPSD->isMemberSpecialization()) {
+      while (!CTPSD->hasMemberSpecialization()) {
         if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
           CTPSD = NewCTPSD;
         else
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 1db02d0d04448c..755ec72f00bf77 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -993,17 +993,7 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const {
   if (const auto *PartialSpec =
           SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
     return PartialSpec->PartialSpecialization->getSpecializedTemplate();
-  return SpecializedTemplate.get<ClassTemplateDecl *>()->getMostRecentDecl();
-}
-
-llvm::PointerUnion<ClassTemplateDecl *,
-                   ClassTemplatePartialSpecializationDecl *>
-ClassTemplateSpecializationDecl::getSpecializedTemplateOrPartial() const {
-  if (const auto *PartialSpec =
-          SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
-    return PartialSpec->PartialSpecialization->getMostRecentDecl();
-
-  return SpecializedTemplate.get<ClassTemplateDecl *>()->getMostRecentDecl();
+  return SpecializedTemplate.get<ClassTemplateDecl*>();
 }
 
 SourceRange
@@ -1293,39 +1283,6 @@ VarTemplateDecl::newCommon(ASTContext &C) const {
   return CommonPtr;
 }
 
-void VarTemplateDecl::mergePrevDecl(VarTemplateDecl *Prev) {
-  // If we haven't created a common pointer yet, then it can just be created
-  // with the usual method.
-  if (!getCommonPtrInternal())
-    return;
-
-  Common *ThisCommon = static_cast<Common *>(getCommonPtrInternal());
-  Common *PrevCommon = nullptr;
-  SmallVector<VarTemplateDecl *, 8> PreviousDecls;
-  for (; Prev; Prev = Prev->getPreviousDecl()) {
-    if (CommonBase *C = Prev->getCommonPtrInternal()) {
-      PrevCommon = static_cast<Common *>(C);
-      break;
-    }
-    PreviousDecls.push_back(Prev);
-  }
-
-  // If the previous redecl chain hasn't created a common pointer yet, then just
-  // use this common pointer.
-  if (!PrevCommon) {
-    for (auto *D : PreviousDecls)
-      D->setCommonPtr(ThisCommon);
-    return;
-  }
-
-  // Ensure we don't leak any important state.
-  assert(ThisCommon->Specializations.empty() &&
-         ThisCommon->PartialSpecializations.empty() &&
-         "Can't merge incompatible declarations!");
-
-  setCommonPtr(PrevCommon);
-}
-
 VarTemplateSpecializationDecl *
 VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args,
                                     void *&InsertPos) {
@@ -1448,16 +1405,7 @@ VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const {
   if (const auto *PartialSpec =
           SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
     return PartialSpec->PartialSpecialization->getSpecializedTemplate();
-  return SpecializedTemplate.get<VarTemplateDecl *>()->getMostRecentDecl();
-}
-
-llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>
-VarTemplateSpecializationDecl::getSpecializedTemplateOrPartial() const {
-  if (const auto *PartialSpec =
-          SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
-    return PartialSpec->PartialSpecialization->getMostRecentDecl();
-
-  return SpecializedTemplate.get<VarTemplateDecl *>()->getMostRecentDecl();
+  return SpecializedTemplate.get<VarTemplateDecl *>();
 }
 
 SourceRange VarTemplateSpecializationDecl::getSourceRange() const {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 00c8f871bbb38c..acb1bee8cef319 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -4694,10 +4694,8 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
 
   // Keep a chain of previous declarations.
   New->setPreviousDecl(Old);
-  if (NewTemplate) {
-    NewTemplate->mergePrevDecl(OldTemplate);
+  if (NewTemplate)
     NewTemplate->setPreviousDecl(OldTemplate);
-  }
 
   // Inherit access appropriately.
   New->setAccess(Old->getAccess());
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index f13355bb93cbeb..cba66d82406cdd 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -9957,7 +9957,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
     auto SynthesizeAggrGuide = [&](InitListExpr *ListInit) {
       auto *Pattern = Template;
       while (Pattern->getInstantiatedFromMemberTemplate()) {
-        if (Pattern->isMemberSpecialization())
+        if (Pattern->hasMemberSpecialization())
           break;
         Pattern = Pattern->getInstantiatedFromMemberTemplate();
       }
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index de0ec0128905ff..b63063813f1b56 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -343,7 +343,7 @@ struct TemplateInstantiationArgumentCollecter
       // If this function was instantiated from a specialized member that is
       // a function template, we're done.
       assert(FD->getPrimaryTemplate() && "No function template?");
-      if (FD->getPrimaryTemplate()->isMemberSpecialization())
+      if (FD->getPrimaryTemplate()->hasMemberSpecialization())
         return Done();
 
       // If this function is a generic lambda specialization, we are done.
@@ -442,11 +442,11 @@ struct TemplateInstantiationArgumentCollecter
         Specialized = CTSD->getSpecializedTemplateOrPartial();
     if (auto *CTPSD =
             Specialized.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
-      if (CTPSD->isMemberSpecialization())
+      if (CTPSD->hasMemberSpecialization())
         return Done();
     } else {
       auto *CTD = Specialized.get<ClassTemplateDecl *>();
-      if (CTD->isMemberSpecialization())
+      if (CTD->hasMemberSpecialization())
         return Done();
     }
     return UseNextDecl(CTSD);
@@ -478,11 +478,11 @@ struct TemplateInstantiationArgumentCollecter
         Specialized = VTSD->getSpecializedTemplateOrPartial();
     if (auto *VTPSD =
             Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
-      if (VTPSD->isMemberSpecialization())
+      if (VTPSD->hasMemberSpecialization())
         return Done();
     } else {
       auto *VTD = Specialized.get<VarTemplateDecl *>();
-      if (VTD->isMemberSpecialization())
+      if (VTD->hasMemberSpecialization())
         return Done();
     }
     return UseNextDecl(VTSD);
@@ -4141,7 +4141,7 @@ getPatternForClassTemplateSpecialization(
   CXXRecordDecl *Pattern = nullptr;
   Specialized = ClassTemplateSpec->getSpecializedTemplateOrPartial();
   if (auto *CTD = Specialized.dyn_cast<ClassTemplateDecl *>()) {
-    while (!CTD->isMemberSpecialization()) {
+    while (!CTD->hasMemberSpecialization()) {
       if (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate())
         CTD = NewCTD;
       else
@@ -4151,7 +4151,7 @@ getPatternForClassTemplateSpecialization(
   } else if (auto *CTPSD =
                  Specialized
                      .dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
-    while (!CTPSD->isMemberSpecialization()) {
+    while (!CTPSD->hasMemberSpecialization()) {
       if (auto *NewCTPSD = CTPSD->getInstantiatedFromMemberTemplate())
         CTPSD = NewCTPSD;
       else
diff --git a/clang/test/AST/ast-dump-decl.cpp b/clang/test/AST/ast-dump-decl.cpp
index 7b998f20944f49..e84241cee922f5 100644
--- a/clang/test/AST/ast-dump-decl.cpp
+++ b/clang/test/AST/ast-dump-decl.cpp
@@ -530,7 +530,7 @@ namespace testCanonicalTemplate {
   // CHECK-NEXT: |   `-ClassTemplateDecl 0x{{.+}} parent 0x{{.+}} <col:5, col:40> col:40 friend_undeclared TestClassTemplate{{$}}
   // CHECK-NEXT: |     |-TemplateTypeParmDecl 0x{{.+}} <col:14, col:23> col:23 typename depth 1 index 0 T2{{$}}
   // CHECK-NEXT: |     `-CXXRecordDecl 0x{{.+}} parent 0x{{.+}} <col:34, col:40> col:40 class TestClassTemplate{{$}}
-  // CHECK-NEXT: `-ClassTemplateSpecializationDecl 0x{{.+}} <col:5, col:40> line:[[@LINE-19]]:31 class TestClassTemplate definition implicit_instantiation{{$}}
+  // CHECK-NEXT: `-ClassTemplateSpecializationDecl 0x{{.+}} <line:[[@LINE-19]]:3, line:[[@LINE-17]]:3> line:[[@LINE-19]]:31 class TestClassTemplate definition implicit_instantiation{{$}}
   // CHECK-NEXT:   |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init{{$}}
   // CHECK-NEXT:   | |-DefaultConstructor exists trivial constexpr defaulted_is_constexpr{{$}}
   // CHECK-NEXT:   | |-CopyConstructor simple trivial has_const_param implicit_has_const_param{{$}}
diff --git a/clang/test/ASTMerge/class-template-spec/Inputs/class-template-spec.cpp b/clang/test/ASTMerge/class-template-spec/Inputs/class-template-spec.cpp
deleted file mode 100644
index 332bf24d25b29d..00000000000000
--- a/clang/test/ASTMerge/class-template-spec/Inputs/class-template-spec.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-namespace N0 {
-  template<typename T>
-  struct A {
-    template<typename U>
-    friend struct A;
-  };
-
-  template struct A<long>;
-} // namespace N0
-
-namespace N1 {
-  template<typename T>
-  struct A;
-
-  template<typename T>
-  struct A {
-    template<typename U>
-    friend struct A;
-  };
-
-  template struct A<long>;
-} // namespace N1
-
-namespace N2 {
-  template<typename T>
-  struct A {
-    template<typename U>
-    friend struct A;
-  };
-
-  template<typename T>
-  struct A;
-
-  template struct A<long>;
-} // namespace N2
-
-namespace N3 {
-  struct A {
-    template<typename T>
-    friend struct B;
-  };
-
-  template<typename T>
-  struct B { };
-
-  template struct B<long>;
-} // namespace N3
diff --git a/clang/test/ASTMerge/class-template-spec/test.cpp b/clang/test/ASTMerge/class-template-spec/test.cpp
deleted file mode 100644
index adbce483503278..00000000000000
--- a/clang/test/ASTMerge/class-template-spec/test.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/class-template-spec.cpp
-// RUN: %clang_cc1 -ast-merge %t.1.ast -fsyntax-only -verify %s
-// expected-no-diagnostics
-
-template struct N0::A<short>;
-template struct N1::A<short>;
-template struct N2::A<short>;
-template struct N3::B<short>;
diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
index e7e4738032f647..87127366eb58a5 100644
--- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
+++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p7.cpp
@@ -177,93 +177,6 @@ namespace Defined {
   static_assert(A<short>::B<int*>::y == 2);
 } // namespace Defined
 
-namespace Constrained {
-  template<typename T>
-  struct A {
-    template<typename U, bool V> requires V
-    static constexpr int f(); // expected-note {{declared here}}
-
-    template<typename U, bool V> requires V
-    static const int x; // expected-note {{declared here}}
-
-    template<typename U, bool V> requires V
-    static const int x<U*, V>; // expected-note {{declared here}}
-
-    template<typename U, bool V> requires V
-    struct B; // expected-note {{template is declared here}}
-
-    template<typename U, bool V> requires V
-    struct B<U*, V>; // expected-note {{template is declared here}}
-  };
-
-  template<>
-  template<typename U, bool V> requires V
-  constexpr int A<short>::f() {
-    return A<long>::f<U, V>();
-  }
-
-  template<>
-  template<typename U, bool V> requires V
-  constexpr int A<short>::x = A<long>::x<U, V>;
-
-  template<>
-  template<typename U, bool V> requires V
-  constexpr int A<short>::x<U*, V> = A<long>::x<U*, V>;
-
-  template<>
-  template<typename U, bool V> requires V
-  struct A<short>::B<U*, V> {
-    static constexpr int y = A<long>::B<U*, V>::y;
-  };
-
-  template<>
-  template<typename U, bool V> requires V
-  struct A<short>::B {
-    static constexpr int y = A<long>::B<U, V>::y;
-  };
-
-  template<>
-  template<typename U, bool V> requires V
-  constexpr int A<long>::f() {
-    return 1;
-  }
-
-  template<>
-  template<typename U, bool V> requires V
-  constexpr int A<long>::x = 1;
-
-  template<>
-  template<typename U, bool V> requires V
-  constexpr int A<long>::x<U*, V> = 2;
-
-  template<>
-  template<typename U, bool V> requires V
-  struct A<long>::B {
-    static constexpr int y = 1;
-  };
-
-  template<>
-  template<typename U, bool V> requires V
-  struct A<long>::B<U*, V> {
-    static constexpr int y = 2;
-  };
-
-  static_assert(A<int>::f<int, true>() == 0); // expected-error {{static assertion expression is not an integral constant expression}}
-                                              // expected-note at -1 {{undefined function 'f<int, true>' cannot be used in a constant expression}}
-  static_assert(A<int>::x<int, true> == 0); // expected-error {{static assertion expression is not an integral constant expression}}
-                                            // expected-note at -1 {{initializer of 'x<int, true>' is unknown}}
-  static_assert(A<int>::x<int*, true> == 0); // expected-error {{static assertion expression is not an integral constant expression}}
-                                             // expected-note at -1 {{initializer of 'x<int *, true>' is unknown}}
-  static_assert(A<int>::B<int, true>::y == 0); // expected-error {{implicit instantiation of undefined template 'Constrained::A<int>::B<int, true>'}}
-  static_assert(A<int>::B<int*, true>::y == 0); // expected-error {{implicit instantiation of undefined template 'Constrained::A<int>::B<int *, true>'}}
-
-  static_assert(A<short>::f<int, true>() == 1);
-  static_assert(A<short>::x<int, true> == 1);
-  static_assert(A<short>::x<int*, true> == 2);
-  static_assert(A<short>::B<int, true>::y == 1);
-  static_assert(A<short>::B<int*, true>::y == 2);
-} // namespace Constrained
-
 namespace Dependent {
   template<int I>
   struct A {



More information about the cfe-commits mailing list