[Concepts] Fix friend-checking to include NTTPs
authorErich Keane <erich.keane@intel.com>
Wed, 16 Nov 2022 15:00:55 +0000 (07:00 -0800)
committerErich Keane <erich.keane@intel.com>
Wed, 16 Nov 2022 15:33:15 +0000 (07:33 -0800)
More work for temp.friend p9, this fixes a previous bug where we didn't
properly consider a friend to depend on the enclosing template if it
only did so via an NTTP.

clang/lib/Sema/SemaTemplate.cpp
clang/test/SemaTemplate/concepts-friends.cpp

index b044586..08ff4f4 100644 (file)
@@ -1707,6 +1707,18 @@ class ConstraintRefersToContainingTemplateChecker
           Result = true;
   }
 
+  void CheckNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+    assert(D->getDepth() <= TemplateDepth &&
+           "Nothing should reference a value below the actual template depth, "
+           "depth is likely wrong");
+    if (D->getDepth() != TemplateDepth)
+      Result = true;
+
+    // Necessary because the type of the NTTP might be what refers to the parent
+    // constriant.
+    TransformType(D->getType());
+  }
+
 public:
   using inherited = TreeTransform<ConstraintRefersToContainingTemplateChecker>;
 
@@ -1742,6 +1754,8 @@ public:
     // unreachable should catch future instances/cases.
     if (auto *TD = dyn_cast<TypedefNameDecl>(D))
       TransformType(TD->getUnderlyingType());
+    else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(D))
+      CheckNonTypeTemplateParmDecl(NTTPD);
     else if (auto *VD = dyn_cast<ValueDecl>(D))
       TransformType(VD->getType());
     else if (auto *TD = dyn_cast<TemplateDecl>(D))
index 6aa4618..3a9b308 100644 (file)
@@ -411,3 +411,33 @@ namespace RefersToParentInConstraint {
     S<long> y;
   }
 } // namespace RefersToParentInConstraint
+
+namespace NTTP {
+  struct Base{};
+  template<int N>
+  struct S : Base {
+    // N is from the parent template.
+    template<typename T>
+      friend int templ_func(Base&) requires(N > 0)
+      { return 10; }
+  };
+
+  template<typename T>
+  struct U : Base {
+    template<T N>
+      friend int templ_func(Base&) requires(N>0)
+      { return 10; }
+  };
+
+  void use() {
+    S<1> s1;
+    templ_func<float>(s1);
+    S<2> s2;
+    templ_func<float>(s2);
+
+    U<int> u1;
+    templ_func<1>(u1);
+    U<short> u2;
+    templ_func<1>(u2);
+  }
+}