[clang] [Clang] support friend declarations with a dependent nested-name-specifier (PR #191268)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 14 06:05:43 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-modules
Author: Oleksandr Tarasiuk (a-tarasyuk)
<details>
<summary>Changes</summary>
Fixes #<!-- -->104057
---
Patch is 90.25 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/191268.diff
29 Files Affected:
- (modified) clang/include/clang/AST/ASTStructuralEquivalence.h (+2)
- (modified) clang/include/clang/AST/DeclFriend.h (+28-89)
- (modified) clang/include/clang/AST/DeclTemplate.h (+31-36)
- (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+3-2)
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+2)
- (modified) clang/include/clang/Sema/Sema.h (+3)
- (modified) clang/include/clang/Sema/Template.h (+1-1)
- (modified) clang/lib/AST/ASTImporter.cpp (+110-15)
- (modified) clang/lib/AST/ASTStructuralEquivalence.cpp (+48)
- (modified) clang/lib/AST/DeclFriend.cpp (+39-25)
- (modified) clang/lib/AST/DeclPrinter.cpp (+5-12)
- (modified) clang/lib/AST/DeclTemplate.cpp (+26-13)
- (modified) clang/lib/Sema/Sema.cpp (+3-2)
- (modified) clang/lib/Sema/SemaAccess.cpp (+329-50)
- (modified) clang/lib/Sema/SemaDeclCXX.cpp (+133-76)
- (modified) clang/lib/Sema/SemaTemplate.cpp (+6-8)
- (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+8-12)
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+64-38)
- (modified) clang/lib/Serialization/ASTReaderDecl.cpp (+7-9)
- (modified) clang/lib/Serialization/ASTWriterDecl.cpp (+7-7)
- (modified) clang/test/CXX/class.access/class.friend/p3-cxx0x.cpp (+2-2)
- (modified) clang/test/CXX/drs/cwg18xx.cpp (+5-6)
- (modified) clang/test/CXX/drs/cwg19xx.cpp (+4-4)
- (modified) clang/test/CXX/drs/cwg6xx.cpp (+10-7)
- (modified) clang/test/CXX/temp/temp.decls/temp.friend/p5.cpp (+138-13)
- (added) clang/test/CXX/temp/temp.decls/temp.friend/p6.cpp (+24)
- (modified) clang/test/SemaCXX/many-template-parameter-lists.cpp (+4-2)
- (modified) clang/test/SemaTemplate/GH71595.cpp (+3-3)
- (modified) clang/test/SemaTemplate/ctad.cpp (+5-4)
``````````diff
diff --git a/clang/include/clang/AST/ASTStructuralEquivalence.h b/clang/include/clang/AST/ASTStructuralEquivalence.h
index 6f82de1ae136d..89d7f8d6ba8ff 100644
--- a/clang/include/clang/AST/ASTStructuralEquivalence.h
+++ b/clang/include/clang/AST/ASTStructuralEquivalence.h
@@ -135,6 +135,8 @@ struct StructuralEquivalenceContext {
/// \c VisitedDecls members) and can cause faulty equivalent results.
bool IsEquivalent(Stmt *S1, Stmt *S2);
+ bool IsEquivalent(TemplateParameterList *TPL1, TemplateParameterList *TPL2);
+
/// Find the index of the given anonymous struct/union within its
/// context.
///
diff --git a/clang/include/clang/AST/DeclFriend.h b/clang/include/clang/AST/DeclFriend.h
index 1f8c210263677..2cd5a1af17fd8 100644
--- a/clang/include/clang/AST/DeclFriend.h
+++ b/clang/include/clang/AST/DeclFriend.h
@@ -15,20 +15,14 @@
#define LLVM_CLANG_AST_DECLFRIEND_H
#include "clang/AST/Decl.h"
-#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/LLVM.h"
-#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
-#include "llvm/Support/TrailingObjects.h"
#include <cassert>
-#include <iterator>
namespace clang {
@@ -49,9 +43,7 @@ class ASTContext;
/// @endcode
///
/// The semantic context of a friend decl is its declaring class.
-class FriendDecl final
- : public Decl,
- private llvm::TrailingObjects<FriendDecl, TemplateParameterList *> {
+class FriendDecl : public Decl {
LLVM_DECLARE_VIRTUAL_ANCHOR_FUNCTION();
public:
@@ -61,46 +53,35 @@ class FriendDecl final
friend class CXXRecordDecl;
friend class CXXRecordDecl::friend_iterator;
- // The declaration that's a friend of this class.
- FriendUnion Friend;
-
- // A pointer to the next friend in the sequence.
- LazyDeclPtr NextFriend;
-
- // Location of the 'friend' specifier.
- SourceLocation FriendLoc;
-
// Location of the '...', if present.
SourceLocation EllipsisLoc;
+ SourceLocation FriendLoc;
+
/// True if this 'friend' declaration is unsupported. Eventually we
/// will support every possible friend declaration, but for now we
/// silently ignore some and set this flag to authorize all access.
LLVM_PREFERRED_TYPE(bool)
unsigned UnsupportedFriend : 1;
- // The number of "outer" template parameter lists in non-templatic
- // (currently unsupported) friend type declarations, such as
- // template <class T> friend class A<T>::B;
- unsigned NumTPLists : 31;
-
- FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend,
- SourceLocation FriendL, SourceLocation EllipsisLoc,
- ArrayRef<TemplateParameterList *> FriendTypeTPLists)
- : Decl(Decl::Friend, DC, L), Friend(Friend), FriendLoc(FriendL),
- EllipsisLoc(EllipsisLoc), UnsupportedFriend(false),
- NumTPLists(FriendTypeTPLists.size()) {
- llvm::copy(FriendTypeTPLists, getTrailingObjects());
- }
+protected:
+ // The declaration that's a friend of this class.
+ FriendUnion Friend;
- FriendDecl(EmptyShell Empty, unsigned NumFriendTypeTPLists)
- : Decl(Decl::Friend, Empty), UnsupportedFriend(false),
- NumTPLists(NumFriendTypeTPLists) {}
+ LazyDeclPtr NextFriend;
+
+ FriendDecl(Kind K, DeclContext *DC, SourceLocation L, FriendUnion Friend,
+ SourceLocation FriendL, SourceLocation EllipsisLoc = {})
+ : Decl(K, DC, L), EllipsisLoc(EllipsisLoc), FriendLoc(FriendL),
+ UnsupportedFriend(false), Friend(Friend), NextFriend() {}
+
+ FriendDecl(Kind K, EmptyShell Empty)
+ : Decl(K, Empty), UnsupportedFriend(false) {}
FriendDecl *getNextFriend() {
- if (!NextFriend.isOffset())
- return cast_or_null<FriendDecl>(NextFriend.get(nullptr));
- return getNextFriendSlowCase();
+ if (NextFriend.isOffset())
+ return getNextFriendSlowCase();
+ return cast_or_null<FriendDecl>(NextFriend.get(nullptr));
}
FriendDecl *getNextFriendSlowCase();
@@ -109,14 +90,11 @@ class FriendDecl final
friend class ASTDeclReader;
friend class ASTDeclWriter;
friend class ASTNodeImporter;
- friend TrailingObjects;
- static FriendDecl *
- Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend_,
- SourceLocation FriendL, SourceLocation EllipsisLoc = {},
- ArrayRef<TemplateParameterList *> FriendTypeTPLists = {});
- static FriendDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
- unsigned FriendTypeNumTPLists);
+ static FriendDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ FriendUnion Friend_, SourceLocation FriendL,
+ SourceLocation EllipsisLoc = {});
+ static FriendDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
/// If this friend declaration names an (untemplated but possibly
/// dependent) type, return the type; otherwise return null. This
@@ -126,58 +104,18 @@ class FriendDecl final
return Friend.dyn_cast<TypeSourceInfo*>();
}
- unsigned getFriendTypeNumTemplateParameterLists() const {
- return NumTPLists;
- }
-
- TemplateParameterList *getFriendTypeTemplateParameterList(unsigned N) const {
- return getTrailingObjects(NumTPLists)[N];
- }
-
/// If this friend declaration doesn't name a type, return the inner
/// declaration.
NamedDecl *getFriendDecl() const {
return Friend.dyn_cast<NamedDecl *>();
}
- /// Retrieves the location of the 'friend' keyword.
- SourceLocation getFriendLoc() const {
- return FriendLoc;
- }
-
/// Retrieves the location of the '...', if present.
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
- /// Retrieves the source range for the friend declaration.
- SourceRange getSourceRange() const override LLVM_READONLY {
- if (TypeSourceInfo *TInfo = getFriendType()) {
- SourceLocation StartL = (NumTPLists == 0)
- ? getFriendLoc()
- : getTrailingObjects()[0]->getTemplateLoc();
- SourceLocation EndL = isPackExpansion() ? getEllipsisLoc()
- : TInfo->getTypeLoc().getEndLoc();
- return SourceRange(StartL, EndL);
- }
-
- if (isPackExpansion())
- return SourceRange(getFriendLoc(), getEllipsisLoc());
-
- if (NamedDecl *ND = getFriendDecl()) {
- if (const auto *FD = dyn_cast<FunctionDecl>(ND))
- return FD->getSourceRange();
- if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(ND))
- return FTD->getSourceRange();
- if (const auto *CTD = dyn_cast<ClassTemplateDecl>(ND))
- return CTD->getSourceRange();
- if (const auto *DD = dyn_cast<DeclaratorDecl>(ND)) {
- if (DD->getOuterLocStart() != DD->getInnerLocStart())
- return DD->getSourceRange();
- }
- return SourceRange(getFriendLoc(), ND->getEndLoc());
- }
-
- return SourceRange(getFriendLoc(), getLocation());
- }
+ SourceLocation getFriendLoc() const { return FriendLoc; }
+
+ SourceRange getSourceRange() const override LLVM_READONLY;
/// Determines if this friend kind is unsupported.
bool isUnsupportedFriend() const {
@@ -191,9 +129,10 @@ class FriendDecl final
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
- static bool classofKind(Kind K) { return K == Decl::Friend; }
+ static bool classofKind(Kind K) {
+ return K == Decl::Friend || K == Decl::FriendTemplate;
+ }
};
-
/// An iterator over the friend declarations of a class.
class CXXRecordDecl::friend_iterator {
friend class CXXRecordDecl;
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index a4a1bb9c13c79..1653c26910b8b 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -19,6 +19,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/Redeclarable.h"
#include "clang/AST/TemplateBase.h"
@@ -2473,42 +2474,43 @@ class ClassTemplateDecl : public RedeclarableTemplateDecl {
///
/// \note This class is not currently in use. All of the above
/// will yield a FriendDecl, not a FriendTemplateDecl.
-class FriendTemplateDecl : public Decl {
- virtual void anchor();
-
-public:
- using FriendUnion = llvm::PointerUnion<NamedDecl *,TypeSourceInfo *>;
+class FriendTemplateDecl final
+ : public FriendDecl,
+ private llvm::TrailingObjects<FriendTemplateDecl,
+ TemplateParameterList *> {
+ void anchor() override;
private:
- // The number of template parameters; always non-zero.
- unsigned NumParams = 0;
+ unsigned NumTPLists : 31;
- // The parameter list.
- TemplateParameterList **Params = nullptr;
-
- // The declaration that's a friend of this class.
- FriendUnion Friend;
-
- // Location of the 'friend' specifier.
- SourceLocation FriendLoc;
-
- FriendTemplateDecl(DeclContext *DC, SourceLocation Loc,
- TemplateParameterList **Params, unsigned NumParams,
- FriendUnion Friend, SourceLocation FriendLoc)
- : Decl(Decl::FriendTemplate, DC, Loc), NumParams(NumParams),
- Params(Params), Friend(Friend), FriendLoc(FriendLoc) {}
+ FriendTemplateDecl(DeclContext *DC, SourceLocation Loc, FriendUnion Friend,
+ SourceLocation FriendLoc, SourceLocation EllipsisLoc,
+ ArrayRef<TemplateParameterList *> FriendTypeTPLists)
+ : FriendDecl(Decl::FriendTemplate, DC, Loc, Friend, FriendLoc,
+ EllipsisLoc),
+ NumTPLists(FriendTypeTPLists.size()) {
+ llvm::copy(FriendTypeTPLists, getTrailingObjects());
+ }
- FriendTemplateDecl(EmptyShell Empty) : Decl(Decl::FriendTemplate, Empty) {}
+ FriendTemplateDecl(EmptyShell Empty, unsigned NumFriendTypeTPLists)
+ : FriendDecl(Decl::FriendTemplate, Empty),
+ NumTPLists(NumFriendTypeTPLists) {}
public:
friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+ friend TrailingObjects;
static FriendTemplateDecl *
Create(ASTContext &Context, DeclContext *DC, SourceLocation Loc,
- MutableArrayRef<TemplateParameterList *> Params, FriendUnion Friend,
- SourceLocation FriendLoc);
+ FriendUnion Friend, SourceLocation FriendLoc,
+ ArrayRef<TemplateParameterList *> FriendTypeTPLists = {},
+ SourceLocation EllipsisLoc = {});
- static FriendTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
+ static FriendTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
+ unsigned FriendTypeNumTPLists);
+
+ SourceRange getSourceRange() const override LLVM_READONLY;
/// If this friend declaration names a templated type (or
/// a dependent member type of a templated type), return that
@@ -2524,19 +2526,12 @@ class FriendTemplateDecl : public Decl {
return Friend.dyn_cast<NamedDecl*>();
}
- /// Retrieves the location of the 'friend' keyword.
- SourceLocation getFriendLoc() const {
- return FriendLoc;
+ TemplateParameterList *getFriendTypeTemplateParameterList(unsigned N) const {
+ assert(N < NumTPLists);
+ return getTrailingObjects()[N];
}
- TemplateParameterList *getTemplateParameterList(unsigned i) const {
- assert(i <= NumParams);
- return Params[i];
- }
-
- unsigned getNumTemplateParameters() const {
- return NumParams;
- }
+ unsigned getFriendTypeNumTemplateParameterLists() const { return NumTPLists; }
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 1a14dd2c666b5..cd4fd5b598d4a 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1727,8 +1727,9 @@ DEF_TRAVERSE_DECL(FriendTemplateDecl, {
TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc()));
else
TRY_TO(TraverseDecl(D->getFriendDecl()));
- for (unsigned I = 0, E = D->getNumTemplateParameters(); I < E; ++I) {
- TemplateParameterList *TPL = D->getTemplateParameterList(I);
+ for (unsigned I = 0, E = D->getFriendTypeNumTemplateParameterLists(); I < E;
+ ++I) {
+ TemplateParameterList *TPL = D->getFriendTypeTemplateParameterList(I);
for (TemplateParameterList::iterator ITPL = TPL->begin(), ETPL = TPL->end();
ITPL != ETPL; ++ITPL) {
TRY_TO(TraverseDecl(*ITPL));
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 4cd4efc55c416..f7e3d8af1dbb8 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1921,6 +1921,8 @@ def err_friend_template_decl_multiple_specifiers: Error<
"a friend declaration that befriends a template must contain exactly one type-specifier">;
def friend_template_decl_malformed_pack_expansion : Error<
"friend declaration expands pack %0 that is declared it its own template parameter list">;
+def err_dependent_friend_not_member : Error<
+ "friend declaration does not name a member of a class template specialization">;
def err_invalid_base_in_interface : Error<
"interface type cannot inherit from "
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 760555d9c8b9b..544d892c1535c 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -12012,6 +12012,9 @@ class Sema final : public SemaBase {
bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous);
void CompleteMemberSpecialization(NamedDecl *Member, LookupResult &Previous);
+ bool CheckDependentFriend(SourceLocation Loc, NestedNameSpecifier NNS,
+ TemplateParameterList *FPL);
+
// Explicit instantiation of a class template specialization
DeclResult ActOnExplicitInstantiation(
Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc,
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index b0170c21feb1a..62b1c16de82c1 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -715,7 +715,7 @@ enum class TemplateSubstitutionKind : char {
// Helper functions for instantiating methods.
TypeSourceInfo *SubstFunctionType(FunctionDecl *D,
- SmallVectorImpl<ParmVarDecl *> &Params);
+ SmallVectorImpl<ParmVarDecl *> &Params);
bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 41ba98c53247d..782e4d710599c 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -537,6 +537,7 @@ namespace clang {
ExpectedDecl VisitFieldDecl(FieldDecl *D);
ExpectedDecl VisitIndirectFieldDecl(IndirectFieldDecl *D);
ExpectedDecl VisitFriendDecl(FriendDecl *D);
+ ExpectedDecl VisitFriendTemplateDecl(FriendTemplateDecl *D);
ExpectedDecl VisitObjCIvarDecl(ObjCIvarDecl *D);
ExpectedDecl VisitVarDecl(VarDecl *D);
ExpectedDecl VisitImplicitParamDecl(ImplicitParamDecl *D);
@@ -4541,10 +4542,40 @@ static bool IsEquivalentFriend(ASTImporter &Importer, FriendDecl *FD1,
Importer.getToContext().getLangOpts(), FD1->getASTContext(),
FD2->getASTContext(), NonEquivalentDecls,
StructuralEquivalenceKind::Default,
- /* StrictTypeSpelling = */ false, /* Complain = */ false);
+ /*StrictTypeSpelling=*/false, /*Complain=*/false);
return Ctx.IsEquivalent(FD1, FD2);
}
+static bool IsEquivalentFriend(ASTImporter &Importer, FriendTemplateDecl *FTD1,
+ FriendTemplateDecl *FTD2) {
+ if (FTD1->getFriendTypeNumTemplateParameterLists() !=
+ FTD2->getFriendTypeNumTemplateParameterLists())
+ return false;
+
+ ASTImporter::NonEquivalentDeclSet NonEquivalentDecls;
+ StructuralEquivalenceContext Ctx(
+ Importer.getToContext().getLangOpts(), FTD1->getASTContext(),
+ FTD2->getASTContext(), NonEquivalentDecls,
+ StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false,
+ /*Complain=*/false);
+
+ for (unsigned I = 0, N = FTD1->getFriendTypeNumTemplateParameterLists();
+ I != N; ++I) {
+ if (!Ctx.IsEquivalent(FTD1->getFriendTypeTemplateParameterList(I),
+ FTD2->getFriendTypeTemplateParameterList(I)))
+ return false;
+ }
+
+ if ((!FTD1->getFriendType()) != (!FTD2->getFriendType()))
+ return false;
+
+ if (const TypeSourceInfo *TSI = FTD1->getFriendType())
+ return Importer.IsStructurallyEquivalent(
+ TSI->getType(), FTD2->getFriendType()->getType(), /*Complain=*/false);
+
+ return Ctx.IsEquivalent(FTD1, FTD2);
+}
+
static FriendCountAndPosition getFriendCountAndPosition(ASTImporter &Importer,
FriendDecl *FD) {
unsigned int FriendCount = 0;
@@ -4561,7 +4592,6 @@ static FriendCountAndPosition getFriendCountAndPosition(ASTImporter &Importer,
}
assert(FriendPosition && "Friend decl not found in own parent.");
-
return {FriendCount, *FriendPosition};
}
@@ -4576,9 +4606,11 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
// We try to maintain order and count of redundant friend declarations.
const auto *RD = cast<CXXRecordDecl>(DC);
SmallVector<FriendDecl *, 2> ImportedEquivalentFriends;
- for (FriendDecl *ImportedFriend : RD->friends())
- if (IsEquivalentFriend(Importer, D, ImportedFriend))
- ImportedEquivalentFriends.push_back(ImportedFriend);
+ for (FriendDecl *ImportedFriend : RD->friends()) {
+ if (ImportedFriend->getKind() == Decl::Friend &&
+ IsEquivalentFriend(Importer, D, cast<FriendDecl>(ImportedFriend)))
+ ImportedEquivalentFriends.push_back(cast<FriendDecl>(ImportedFriend));
+ }
FriendCountAndPosition CountAndPosition =
getFriendCountAndPosition(Importer, D);
@@ -4609,15 +4641,6 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
return TSIOrErr.takeError();
}
- SmallVector<TemplateParameterList *, 1> ToTPLists(D->NumTPLists);
- auto **FromTPLists = D->getTrailingObjects();
- for (unsigned I = 0; I < D->NumTPLists; I++) {
- if (auto ListOrErr = import(FromTPLists[I]))
- ToTPLists[I] = *ListOrErr;
- else
- return ListOrErr.takeError();
- }
-
auto LocationOrErr = import(D->getLocation());
if (!LocationOrErr)
return LocationOrErr.takeError();
@@ -4631,7 +4654,7 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
FriendDecl *FrD;
if (GetImportedOrCreateDecl(FrD, D, Importer.getToContext(), DC,
*LocationOrErr, ToFU, *FriendLocOrErr,
- *EllipsisLocOrErr, ToTPLists))
+ *EllipsisLocOrErr))
return FrD;
FrD->setAccess(D->getAccess());
@@ -4640,6 +4663,78 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
return FrD;
}
+ExpectedDecl ASTNodeImporter::VisitFriendTemplateDecl(FriendTemplateDecl *D) {
+ DeclContext *DC, *LexicalDC;
+ if (Error Err = ImportDeclContext(D, DC, LexicalDC))
+ return std::move(Err);
+
+ const auto *RD = cast<CXXRecordDecl>(DC);
+ SmallVector<FriendTemplateDecl *, 2> ImportedEquivalentFriends;
+ for (FriendDecl *ImportedFriend : RD->friends()) {
+ if (isa<FriendTemplateDecl>(ImportedFriend) &&
+ IsEquivalentFriend(Importer, D,
+ cast<FriendTemplateDecl>(ImportedFriend)))
+ ImportedEquivalentFriends.push_back(
+ cast<FriendTemplateDecl>(ImportedFriend));
+ }
+
+ FriendCountAndPosition CountAndPosition =
+ getFriendCountAndPosition(Importer, D);
+ assert(ImportedEquivalentFriends.size() <= CountAndPosition.TotalCount &&
+ "Class with non-...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/191268
More information about the cfe-commits
mailing list