Close https://github.com/llvm/llvm-project/issues/218228 The root cause of the problem is the corresponding friend is not loaded at the point of ADL. This patch tries to fix this simply by loading the friends at the point of ADL. Note that this may be best efficient if there are a lot of friends. We just think it is rare. If it is really possible, we can change the structure of friends from a list to a name lookup table. (cherry picked from commit 01aedf3b34325ad2f74a77325a2da9a7e36ae3d5)
84 lines
3.0 KiB
C++
84 lines
3.0 KiB
C++
//===- DeclFriend.cpp - C++ Friend Declaration AST Node Implementation ----===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the AST classes related to C++ friend
|
|
// declarations.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/AST/DeclFriend.h"
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/AST/Decl.h"
|
|
#include "clang/AST/DeclBase.h"
|
|
#include "clang/AST/DeclCXX.h"
|
|
#include "clang/AST/DeclTemplate.h"
|
|
#include "clang/Basic/LLVM.h"
|
|
#include <cassert>
|
|
#include <cstddef>
|
|
|
|
using namespace clang;
|
|
|
|
void FriendDecl::anchor() {}
|
|
|
|
FriendDecl *FriendDecl::getNextFriendSlowCase() {
|
|
return cast_or_null<FriendDecl>(
|
|
NextFriend.get(getASTContext().getExternalSource()));
|
|
}
|
|
|
|
FriendDecl *
|
|
FriendDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
|
|
FriendUnion Friend, SourceLocation FriendL,
|
|
SourceLocation EllipsisLoc,
|
|
ArrayRef<TemplateParameterList *> FriendTypeTPLists) {
|
|
#ifndef NDEBUG
|
|
if (const auto *D = dyn_cast<NamedDecl *>(Friend)) {
|
|
assert(isa<FunctionDecl>(D) ||
|
|
isa<CXXRecordDecl>(D) ||
|
|
isa<FunctionTemplateDecl>(D) ||
|
|
isa<ClassTemplateDecl>(D));
|
|
|
|
// As a temporary hack, we permit template instantiation to point
|
|
// to the original declaration when instantiating members.
|
|
assert(D->getFriendObjectKind() ||
|
|
(cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind()));
|
|
// These template parameters are for friend types only.
|
|
assert(FriendTypeTPLists.empty());
|
|
}
|
|
#endif
|
|
|
|
std::size_t Extra =
|
|
FriendDecl::additionalSizeToAlloc<TemplateParameterList *>(
|
|
FriendTypeTPLists.size());
|
|
auto *FD = new (C, DC, Extra)
|
|
FriendDecl(DC, L, Friend, FriendL, EllipsisLoc, FriendTypeTPLists);
|
|
cast<CXXRecordDecl>(DC)->pushFriendDecl(FD);
|
|
return FD;
|
|
}
|
|
|
|
FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID,
|
|
unsigned FriendTypeNumTPLists) {
|
|
std::size_t Extra =
|
|
additionalSizeToAlloc<TemplateParameterList *>(FriendTypeNumTPLists);
|
|
return new (C, ID, Extra) FriendDecl(EmptyShell(), FriendTypeNumTPLists);
|
|
}
|
|
|
|
FriendDecl *CXXRecordDecl::getFirstFriend() const {
|
|
ExternalASTSource *Source = getParentASTContext().getExternalSource();
|
|
Decl *First = data().FirstFriend.get(Source);
|
|
return First ? cast<FriendDecl>(First) : nullptr;
|
|
}
|
|
|
|
void CXXRecordDecl::loadLazyFriends() {
|
|
assert(hasDefinition());
|
|
assert(hasLazyFriends());
|
|
ExternalASTSource *Source = getParentASTContext().getExternalSource();
|
|
FriendDecl *Friend = cast_or_null<FriendDecl>(data().FirstFriend.get(Source));
|
|
while (Friend && Friend->NextFriend.isOffset())
|
|
Friend = cast_or_null<FriendDecl>(Friend->NextFriend.get(Source));
|
|
}
|