[Concepts] Fix friend-checking to include NTTPs

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.
This commit is contained in:
Erich Keane 2022-11-16 07:00:55 -08:00
parent ed4943d560
commit 6c38ffc7b6
2 changed files with 44 additions and 0 deletions

View 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))

View 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);
}
}