Skip to content

Commit

Permalink
[Concepts] Fix friend duplicate detection when referencing containing…
Browse files Browse the repository at this point in the history
… Record

As another regression from the Deferred Concepts Instantiation patch, we
weren't properly detecting that a friend referenced its containing
Record when it referred to it without its template parameters.  This
patch makes sure that we do.
  • Loading branch information
Erich Keane committed Oct 7, 2022
1 parent 1d1c755 commit 853df5e
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 6 deletions.
6 changes: 4 additions & 2 deletions clang/include/clang/Sema/Sema.h
Expand Up @@ -3686,8 +3686,10 @@ class Sema final {
// template, or just the current friend function. A 'lower' TemplateDepth in
// the AST refers to a 'containing' template. As the constraint is
// uninstantiated, this is relative to the 'top' of the TU.
bool ConstraintExpressionDependsOnEnclosingTemplate(unsigned TemplateDepth,
const Expr *Constraint);
bool
ConstraintExpressionDependsOnEnclosingTemplate(const FunctionDecl *Friend,
unsigned TemplateDepth,
const Expr *Constraint);

// Calculates whether the friend function depends on an enclosing template for
// the purposes of [temp.friend] p9.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaConcept.cpp
Expand Up @@ -657,7 +657,7 @@ bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) {

unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD);
for (const Expr *Constraint : ACs)
if (ConstraintExpressionDependsOnEnclosingTemplate(OldTemplateDepth,
if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth,
Constraint))
return true;

Expand Down
25 changes: 22 additions & 3 deletions clang/lib/Sema/SemaTemplate.cpp
Expand Up @@ -1691,14 +1691,28 @@ namespace {
class ConstraintRefersToContainingTemplateChecker
: public TreeTransform<ConstraintRefersToContainingTemplateChecker> {
bool Result = false;
const FunctionDecl *Friend = nullptr;
unsigned TemplateDepth = 0;

// Check a record-decl that we've seen to see if it is a lexical parent of the
// Friend, likely because it was referred to without its template arguments.
void CheckIfContainingRecord(const CXXRecordDecl *CheckingRD) {
CheckingRD = CheckingRD->getMostRecentDecl();

for (const DeclContext *DC = Friend->getLexicalDeclContext();
DC && !DC->isFileContext(); DC = DC->getParent())
if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
if (CheckingRD == RD->getMostRecentDecl())
Result = true;
}

public:
using inherited = TreeTransform<ConstraintRefersToContainingTemplateChecker>;

ConstraintRefersToContainingTemplateChecker(Sema &SemaRef,
const FunctionDecl *Friend,
unsigned TemplateDepth)
: inherited(SemaRef), TemplateDepth(TemplateDepth) {}
: inherited(SemaRef), Friend(Friend), TemplateDepth(TemplateDepth) {}
bool getResult() const { return Result; }

// This should be the only template parm type that we have to deal with.
Expand Down Expand Up @@ -1728,6 +1742,8 @@ class ConstraintRefersToContainingTemplateChecker
TransformType(VD->getType());
else if (auto *TD = dyn_cast<TemplateDecl>(D))
TransformTemplateParameterList(TD->getTemplateParameters());
else if (auto *RD = dyn_cast<CXXRecordDecl>(D))
CheckIfContainingRecord(RD);
else if (isa<NamedDecl>(D)) {
// No direct types to visit here I believe.
} else
Expand All @@ -1738,8 +1754,11 @@ class ConstraintRefersToContainingTemplateChecker
} // namespace

bool Sema::ConstraintExpressionDependsOnEnclosingTemplate(
unsigned TemplateDepth, const Expr *Constraint) {
ConstraintRefersToContainingTemplateChecker Checker(*this, TemplateDepth);
const FunctionDecl *Friend, unsigned TemplateDepth,
const Expr *Constraint) {
assert(Friend->getFriendObjectKind() && "Only works on a friend");
ConstraintRefersToContainingTemplateChecker Checker(*this, Friend,
TemplateDepth);
Checker.TransformExpr(const_cast<Expr *>(Constraint));
return Checker.getResult();
}
Expand Down
17 changes: 17 additions & 0 deletions clang/test/SemaTemplate/concepts-friends.cpp
Expand Up @@ -394,3 +394,20 @@ namespace NamedDeclRefs {
// expected-note@#NOREFOUTER{{previous definition is here}}
}
} // namespace NamedDeclRefs

namespace RefersToParentInConstraint {
// No diagnostic, these aren't duplicates.
template<typename T, typename U>
concept similar = true;

template <typename X>
struct S{
friend void f(similar<S> auto && self){}
friend void f2(similar<S<X>> auto && self){}
};

void use() {
S<int> x;
S<long> y;
}
} // namespace RefersToParentInConstraint

0 comments on commit 853df5e

Please sign in to comment.