Skip to content
This repository was archived by the owner on Mar 30, 2021. It is now read-only.

Commit bf73078

Browse files
authored
Compare the DC of the underlying type of a FriendDecl (#625)
1 parent b74662d commit bf73078

File tree

2 files changed

+74
-7
lines changed

2 files changed

+74
-7
lines changed

lib/AST/ASTImporter.cpp

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3363,6 +3363,30 @@ getFriendCountAndPosition(FriendDecl *FD) {
33633363
return std::make_tuple(FriendCount, *FriendPosition);
33643364
}
33653365

3366+
// Returns the DeclContext of the underlying friend declaration/type. If that
3367+
// is a dependent type then the returned optional does not have a value.
3368+
static Optional<DeclContext *> getDCOfUnderlyingDecl(FriendDecl *FrD) {
3369+
if (NamedDecl *ND = FrD->getFriendDecl())
3370+
return ND->getDeclContext();
3371+
if (FrD->getFriendType()) {
3372+
QualType Ty = FrD->getFriendType()->getType();
3373+
if (isa<ElaboratedType>(Ty))
3374+
Ty = cast<ElaboratedType>(Ty)->getNamedType();
3375+
if (!Ty->isDependentType()) {
3376+
if (const auto *RTy = dyn_cast<RecordType>(Ty))
3377+
return RTy->getAsCXXRecordDecl()->getDeclContext();
3378+
else if (const auto *SpecTy = dyn_cast<TemplateSpecializationType>(Ty))
3379+
return SpecTy->getAsCXXRecordDecl()->getDeclContext();
3380+
else if (const auto TypedefTy = dyn_cast<TypedefType>(Ty))
3381+
return TypedefTy->getDecl()->getDeclContext();
3382+
else
3383+
llvm_unreachable("Unhandled type of friend");
3384+
}
3385+
}
3386+
// DependentType
3387+
return Optional<DeclContext *>();
3388+
}
3389+
33663390
ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
33673391
// Import the major distinguishing characteristics of a declaration.
33683392
DeclContext *DC, *LexicalDC;
@@ -3373,25 +3397,39 @@ ExpectedDecl ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
33733397
// FriendDecl is not a NamedDecl so we cannot use lookup.
33743398
// We try to maintain order and count of redundant friend declarations.
33753399
auto *RD = cast<CXXRecordDecl>(DC);
3376-
FriendDecl *ImportedFriend = RD->getFirstFriend();
33773400
SmallVector<FriendDecl *, 2> ImportedEquivalentFriends;
33783401

3379-
while (ImportedFriend) {
3402+
for (FriendDecl *ImportedFriend = RD->getFirstFriend(); ImportedFriend;
3403+
ImportedFriend = ImportedFriend->getNextFriend()) {
3404+
3405+
// Compare the semantic DeclContext of the underlying declarations of the
3406+
// existing and the to be imported friend.
3407+
// Normally, lookup ensures this, but with friends we cannot use the lookup.
3408+
Optional<DeclContext *> ImportedFriendDC =
3409+
getDCOfUnderlyingDecl(ImportedFriend);
3410+
Optional<DeclContext *> FromFriendDC = getDCOfUnderlyingDecl(D);
3411+
if (FromFriendDC) { // The underlying friend type is not dependent.
3412+
ExpectedDecl FriendDCDeclOrErr = import(cast<Decl>(*FromFriendDC));
3413+
if (!FriendDCDeclOrErr)
3414+
return FriendDCDeclOrErr.takeError();
3415+
DeclContext *FriendDC = cast<DeclContext>(*FriendDCDeclOrErr);
3416+
if (ImportedFriendDC != FriendDC)
3417+
continue;
3418+
}
3419+
33803420
bool Match = false;
3381-
if (D->getFriendDecl() && ImportedFriend->getFriendDecl()) {
3421+
if (D->getFriendDecl() && ImportedFriend->getFriendDecl())
33823422
Match =
33833423
isStructuralMatch(D->getFriendDecl(), ImportedFriend->getFriendDecl(),
33843424
/*Complain=*/false);
3385-
} else if (D->getFriendType() && ImportedFriend->getFriendType()) {
3425+
else if (D->getFriendType() && ImportedFriend->getFriendType())
33863426
Match = Importer.IsStructurallyEquivalent(
33873427
D->getFriendType()->getType(),
33883428
ImportedFriend->getFriendType()->getType(), /*Complain=*/false);
3389-
}
33903429
if (Match)
33913430
ImportedEquivalentFriends.push_back(ImportedFriend);
3392-
3393-
ImportedFriend = ImportedFriend->getNextFriend();
33943431
}
3432+
33953433
std::tuple<unsigned int, unsigned int> CountAndPosition =
33963434
getFriendCountAndPosition(D);
33973435

unittests/AST/ASTImporterTest.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3724,6 +3724,35 @@ TEST_P(ImportFriendClasses, ImportOfClassDefinitionAndFwdFriendShouldBeLinked) {
37243724
EXPECT_EQ(ImportedFwd, ImportedDef->getPreviousDecl());
37253725
}
37263726

3727+
TEST_P(ImportFriendClasses, ImportOfInlineFriendClassAfterFwdWithSameName) {
3728+
auto Code =
3729+
R"(
3730+
class Container {
3731+
friend class X; // A friend class ::X
3732+
class X{ };
3733+
friend class X; // Friend class Container::X
3734+
};
3735+
)";
3736+
Decl *FromTu = getTuDecl(Code, Lang_CXX, "from.cc");
3737+
3738+
auto *To = Import(FirstDeclMatcher<CXXRecordDecl>().match(
3739+
FromTu, cxxRecordDecl(hasName("Container"))),
3740+
Lang_CXX);
3741+
ASSERT_TRUE(To);
3742+
3743+
Decl *ToTu = To->getTranslationUnitDecl();
3744+
auto *ToFriend1 = FirstDeclMatcher<FriendDecl>().match(ToTu, friendDecl());
3745+
auto *ToFriend2 = LastDeclMatcher<FriendDecl>().match(ToTu, friendDecl());
3746+
auto *ToX = FirstDeclMatcher<RecordDecl>().match(
3747+
ToTu, cxxRecordDecl(hasName("X"), unless(isImplicit())));
3748+
3749+
EXPECT_NE(ToFriend1, ToFriend2);
3750+
const RecordDecl *RecordOfFriend1 = getRecordDeclOfFriend(ToFriend1);
3751+
const RecordDecl *RecordOfFriend2 = getRecordDeclOfFriend(ToFriend2);
3752+
EXPECT_NE(RecordOfFriend1, ToX);
3753+
EXPECT_EQ(RecordOfFriend2, ToX);
3754+
}
3755+
37273756
struct DeclContextTest : ASTImporterOptionSpecificTestBase {};
37283757

37293758
TEST_P(DeclContextTest, removeDeclOfClassTemplateSpecialization) {

0 commit comments

Comments
 (0)