forked from OSchip/llvm-project
[ASTImporter] FriendDecl importing improvements
There are only a few cases of importing a frienddecl which is currently supported. This patch aims to improve the friend import process. Set FriendObjectKind in case of decls, insert friend into the friend chain correctly, checks structurally equivalent in a more advanced manner. Test cases added as well. llvm-svn: 330847
This commit is contained in:
parent
cd8688a4c2
commit
b180eebed4
|
@ -309,6 +309,7 @@ private:
|
|||
protected:
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
friend class ASTImporter;
|
||||
friend class ASTReader;
|
||||
friend class CXXClassMemberWrapper;
|
||||
friend class LinkageComputer;
|
||||
|
|
|
@ -273,6 +273,8 @@ def note_odr_objc_synthesize_ivar_here : Note<
|
|||
"property is synthesized to ivar %0 here">;
|
||||
|
||||
// Importing C++ ASTs
|
||||
def note_odr_friend : Note<"friend declared here">;
|
||||
def note_odr_missing_friend : Note<"no corresponding friend here">;
|
||||
def err_odr_different_num_template_parameters : Error<
|
||||
"template parameter lists have a different number of parameters (%0 vs %1)">;
|
||||
def note_odr_template_parameter_list : Note<
|
||||
|
|
|
@ -2709,9 +2709,14 @@ Decl *ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
|
|||
|
||||
// Not found. Create it.
|
||||
FriendDecl::FriendUnion ToFU;
|
||||
if (NamedDecl *FriendD = D->getFriendDecl())
|
||||
ToFU = cast_or_null<NamedDecl>(Importer.Import(FriendD));
|
||||
else
|
||||
if (NamedDecl *FriendD = D->getFriendDecl()) {
|
||||
auto *ToFriendD = cast_or_null<NamedDecl>(Importer.Import(FriendD));
|
||||
if (ToFriendD && FriendD->getFriendObjectKind() != Decl::FOK_None &&
|
||||
!(FriendD->isInIdentifierNamespace(Decl::IDNS_NonMemberOperator)))
|
||||
ToFriendD->setObjectOfFriendDecl(false);
|
||||
|
||||
ToFU = ToFriendD;
|
||||
} else // The friend is a type, not a decl.
|
||||
ToFU = Importer.Import(D->getFriendType());
|
||||
if (!ToFU)
|
||||
return nullptr;
|
||||
|
@ -2731,7 +2736,6 @@ Decl *ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
|
|||
ToTPLists);
|
||||
|
||||
Importer.Imported(D, FrD);
|
||||
RD->pushFriendDecl(FrD);
|
||||
|
||||
FrD->setAccess(D->getAccess());
|
||||
FrD->setLexicalDeclContext(LexicalDC);
|
||||
|
@ -6596,7 +6600,7 @@ Decl *ASTImporter::Import(Decl *FromD) {
|
|||
|
||||
// Record the imported declaration.
|
||||
ImportedDecls[FromD] = ToD;
|
||||
|
||||
ToD->IdentifierNamespace = FromD->IdentifierNamespace;
|
||||
return ToD;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclFriend.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/NestedNameSpecifier.h"
|
||||
|
@ -942,6 +943,44 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the friends for consistency.
|
||||
CXXRecordDecl::friend_iterator Friend2 = D2CXX->friend_begin(),
|
||||
Friend2End = D2CXX->friend_end();
|
||||
for (CXXRecordDecl::friend_iterator Friend1 = D1CXX->friend_begin(),
|
||||
Friend1End = D1CXX->friend_end();
|
||||
Friend1 != Friend1End; ++Friend1, ++Friend2) {
|
||||
if (Friend2 == Friend2End) {
|
||||
if (Context.Complain) {
|
||||
Context.Diag2(D2->getLocation(),
|
||||
diag::warn_odr_tag_type_inconsistent)
|
||||
<< Context.ToCtx.getTypeDeclType(D2CXX);
|
||||
Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
|
||||
Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsStructurallyEquivalent(Context, *Friend1, *Friend2)) {
|
||||
if (Context.Complain) {
|
||||
Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
|
||||
<< Context.ToCtx.getTypeDeclType(D2CXX);
|
||||
Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
|
||||
Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Friend2 != Friend2End) {
|
||||
if (Context.Complain) {
|
||||
Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
|
||||
<< Context.ToCtx.getTypeDeclType(D2);
|
||||
Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
|
||||
Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else if (D1CXX->getNumBases() > 0) {
|
||||
if (Context.Complain) {
|
||||
Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
|
||||
|
@ -1184,6 +1223,31 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
|||
D2->getTemplatedDecl()->getType());
|
||||
}
|
||||
|
||||
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
||||
FriendDecl *D1, FriendDecl *D2) {
|
||||
if ((D1->getFriendType() && D2->getFriendDecl()) ||
|
||||
(D1->getFriendDecl() && D2->getFriendType())) {
|
||||
return false;
|
||||
}
|
||||
if (D1->getFriendType() && D2->getFriendType())
|
||||
return IsStructurallyEquivalent(Context,
|
||||
D1->getFriendType()->getType(),
|
||||
D2->getFriendType()->getType());
|
||||
if (D1->getFriendDecl() && D2->getFriendDecl())
|
||||
return IsStructurallyEquivalent(Context, D1->getFriendDecl(),
|
||||
D2->getFriendDecl());
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
||||
FunctionDecl *D1, FunctionDecl *D2) {
|
||||
// FIXME: Consider checking for function attributes as well.
|
||||
if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Determine structural equivalence of two declarations.
|
||||
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
||||
Decl *D1, Decl *D2) {
|
||||
|
@ -1381,6 +1445,25 @@ bool StructuralEquivalenceContext::Finish() {
|
|||
// Kind mismatch.
|
||||
Equivalent = false;
|
||||
}
|
||||
} else if (FunctionDecl *FD1 = dyn_cast<FunctionDecl>(D1)) {
|
||||
if (FunctionDecl *FD2 = dyn_cast<FunctionDecl>(D2)) {
|
||||
if (!::IsStructurallyEquivalent(FD1->getIdentifier(),
|
||||
FD2->getIdentifier()))
|
||||
Equivalent = false;
|
||||
if (!::IsStructurallyEquivalent(*this, FD1, FD2))
|
||||
Equivalent = false;
|
||||
} else {
|
||||
// Kind mismatch.
|
||||
Equivalent = false;
|
||||
}
|
||||
} else if (FriendDecl *FrD1 = dyn_cast<FriendDecl>(D1)) {
|
||||
if (FriendDecl *FrD2 = dyn_cast<FriendDecl>(D2)) {
|
||||
if (!::IsStructurallyEquivalent(*this, FrD1, FrD2))
|
||||
Equivalent = false;
|
||||
} else {
|
||||
// Kind mismatch.
|
||||
Equivalent = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Equivalent) {
|
||||
|
|
|
@ -18,3 +18,31 @@ struct C {
|
|||
enum E {
|
||||
b = 1
|
||||
};
|
||||
|
||||
//Friend import tests
|
||||
void f();
|
||||
int g(int a);
|
||||
struct X;
|
||||
struct Y;
|
||||
|
||||
struct F1 {
|
||||
public:
|
||||
int x;
|
||||
friend struct X;
|
||||
friend int g(int);
|
||||
friend void f();
|
||||
};
|
||||
|
||||
struct F2 {
|
||||
public:
|
||||
int x;
|
||||
friend struct X;
|
||||
friend void f();
|
||||
};
|
||||
|
||||
struct F3 {
|
||||
public:
|
||||
int x;
|
||||
friend int g(int);
|
||||
friend void f();
|
||||
};
|
||||
|
|
|
@ -12,3 +12,29 @@ enum E {
|
|||
a = 0,
|
||||
b = 1
|
||||
};
|
||||
|
||||
//Friend import tests
|
||||
void f();
|
||||
int g(int a);
|
||||
struct X;
|
||||
struct Y;
|
||||
|
||||
struct F1 {
|
||||
public:
|
||||
int x;
|
||||
friend struct X;
|
||||
friend int g(int);
|
||||
friend void f();
|
||||
};
|
||||
|
||||
struct F2 {
|
||||
public:
|
||||
int x;
|
||||
friend struct X;
|
||||
};
|
||||
|
||||
struct F3 {
|
||||
public:
|
||||
int x;
|
||||
friend void f();
|
||||
};
|
||||
|
|
|
@ -12,3 +12,13 @@
|
|||
// CHECK: class1.cpp:18:6: warning: type 'E' has incompatible definitions in different translation units
|
||||
// CHECK: class1.cpp:19:3: note: enumerator 'b' with value 1 here
|
||||
// CHECK: class2.cpp:12:3: note: enumerator 'a' with value 0 here
|
||||
|
||||
// CHECK: class1.cpp:36:8: warning: type 'F2' has incompatible definitions in different translation units
|
||||
// CHECK: class1.cpp:39:3: note: friend declared here
|
||||
// CHECK: class2.cpp:30:8: note: no corresponding friend here
|
||||
|
||||
// CHECK: class1.cpp:43:8: warning: type 'F3' has incompatible definitions in different translation units
|
||||
// CHECK: class1.cpp:46:3: note: friend declared here
|
||||
// CHECK: class2.cpp:36:8: note: no corresponding friend here
|
||||
|
||||
// CHECK: 4 warnings generated.
|
||||
|
|
Loading…
Reference in New Issue