mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-11 02:16:50 +00:00
Implement declaration merging for non-template functions from
different modules. This implementation is a first approximation of what we want, using only the function type to determine equivalence. Later, we'll want to deal with some of the more subtle issues, including: - C allows a prototyped declaration and a non-prototyped declaration to be merged, which we should support - We may want to ignore the return type when merging, then complain if the return types differ. Or, we may want to leave it as it us, so that we only complain if overload resolution eventually fails. - C++ non-static member functions need to consider cv-qualifiers and ref-qualifiers. - Function templates need to consider the template parameters and return type. - Function template specializations will have special rules. - We can now (accidentally!) end up overloading in C, even without the "overloadable" attribute, and will need to detect this at some point. The actual detection of "is this an overload?" is implemented by Sema::IsOverload(), which will need to be moved into the AST library for re-use here. That will be a future refactor. llvm-svn: 147534
This commit is contained in:
parent
9b7b39116e
commit
b258569405
@ -490,14 +490,38 @@ void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
|
void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
|
||||||
VisitRedeclarable(FD);
|
// Record the declaration -> global ID mapping.
|
||||||
|
Reader.DeclToID[FD] = ThisDeclID;
|
||||||
|
|
||||||
|
RedeclarableResult Redecl = VisitRedeclarable(FD);
|
||||||
VisitDeclaratorDecl(FD);
|
VisitDeclaratorDecl(FD);
|
||||||
|
|
||||||
ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName(), Record, Idx);
|
ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName(), Record, Idx);
|
||||||
FD->IdentifierNamespace = Record[Idx++];
|
FD->IdentifierNamespace = Record[Idx++];
|
||||||
|
|
||||||
|
// FunctionDecl's body is handled last at ASTDeclReader::Visit,
|
||||||
|
// after everything else is read.
|
||||||
|
|
||||||
|
FD->SClass = (StorageClass)Record[Idx++];
|
||||||
|
FD->SClassAsWritten = (StorageClass)Record[Idx++];
|
||||||
|
FD->IsInline = Record[Idx++];
|
||||||
|
FD->IsInlineSpecified = Record[Idx++];
|
||||||
|
FD->IsVirtualAsWritten = Record[Idx++];
|
||||||
|
FD->IsPure = Record[Idx++];
|
||||||
|
FD->HasInheritedPrototype = Record[Idx++];
|
||||||
|
FD->HasWrittenPrototype = Record[Idx++];
|
||||||
|
FD->IsDeleted = Record[Idx++];
|
||||||
|
FD->IsTrivial = Record[Idx++];
|
||||||
|
FD->IsDefaulted = Record[Idx++];
|
||||||
|
FD->IsExplicitlyDefaulted = Record[Idx++];
|
||||||
|
FD->HasImplicitReturnZero = Record[Idx++];
|
||||||
|
FD->IsConstexpr = Record[Idx++];
|
||||||
|
FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
|
||||||
|
|
||||||
switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
|
switch ((FunctionDecl::TemplatedKind)Record[Idx++]) {
|
||||||
default: llvm_unreachable("Unhandled TemplatedKind!");
|
default: llvm_unreachable("Unhandled TemplatedKind!");
|
||||||
case FunctionDecl::TK_NonTemplate:
|
case FunctionDecl::TK_NonTemplate:
|
||||||
|
mergeRedeclarable(FD, Redecl);
|
||||||
break;
|
break;
|
||||||
case FunctionDecl::TK_FunctionTemplate:
|
case FunctionDecl::TK_FunctionTemplate:
|
||||||
FD->setDescribedFunctionTemplate(ReadDeclAs<FunctionTemplateDecl>(Record,
|
FD->setDescribedFunctionTemplate(ReadDeclAs<FunctionTemplateDecl>(Record,
|
||||||
@ -591,25 +615,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FunctionDecl's body is handled last at ASTDeclReader::Visit,
|
|
||||||
// after everything else is read.
|
|
||||||
|
|
||||||
FD->SClass = (StorageClass)Record[Idx++];
|
|
||||||
FD->SClassAsWritten = (StorageClass)Record[Idx++];
|
|
||||||
FD->IsInline = Record[Idx++];
|
|
||||||
FD->IsInlineSpecified = Record[Idx++];
|
|
||||||
FD->IsVirtualAsWritten = Record[Idx++];
|
|
||||||
FD->IsPure = Record[Idx++];
|
|
||||||
FD->HasInheritedPrototype = Record[Idx++];
|
|
||||||
FD->HasWrittenPrototype = Record[Idx++];
|
|
||||||
FD->IsDeleted = Record[Idx++];
|
|
||||||
FD->IsTrivial = Record[Idx++];
|
|
||||||
FD->IsDefaulted = Record[Idx++];
|
|
||||||
FD->IsExplicitlyDefaulted = Record[Idx++];
|
|
||||||
FD->HasImplicitReturnZero = Record[Idx++];
|
|
||||||
FD->IsConstexpr = Record[Idx++];
|
|
||||||
FD->EndRangeLoc = ReadSourceLocation(Record, Idx);
|
|
||||||
|
|
||||||
// Read in the parameters.
|
// Read in the parameters.
|
||||||
unsigned NumParams = Record[Idx++];
|
unsigned NumParams = Record[Idx++];
|
||||||
SmallVector<ParmVarDecl *, 16> Params;
|
SmallVector<ParmVarDecl *, 16> Params;
|
||||||
@ -1696,12 +1701,19 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) {
|
|||||||
// Compatible tags match.
|
// Compatible tags match.
|
||||||
if (TagDecl *TagX = dyn_cast<TagDecl>(X)) {
|
if (TagDecl *TagX = dyn_cast<TagDecl>(X)) {
|
||||||
TagDecl *TagY = cast<TagDecl>(Y);
|
TagDecl *TagY = cast<TagDecl>(Y);
|
||||||
if ((TagX->getTagKind() == TagY->getTagKind()) ||
|
return (TagX->getTagKind() == TagY->getTagKind()) ||
|
||||||
((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class)&&
|
((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class) &&
|
||||||
(TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class)))
|
(TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Functions with the same type and linkage match.
|
||||||
|
if (FunctionDecl *FuncX = dyn_cast<FunctionDecl>(X)) {
|
||||||
|
FunctionDecl *FuncY = cast<FunctionDecl>(Y);
|
||||||
|
return (FuncX->getLinkage() == FuncY->getLinkage()) &&
|
||||||
|
FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// FIXME: Many other cases to implement.
|
// FIXME: Many other cases to implement.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -302,6 +302,26 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
|
|||||||
|
|
||||||
Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
|
Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record);
|
||||||
Record.push_back(D->getIdentifierNamespace());
|
Record.push_back(D->getIdentifierNamespace());
|
||||||
|
|
||||||
|
// FunctionDecl's body is handled last at ASTWriterDecl::Visit,
|
||||||
|
// after everything else is written.
|
||||||
|
|
||||||
|
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
|
||||||
|
Record.push_back(D->getStorageClassAsWritten());
|
||||||
|
Record.push_back(D->IsInline);
|
||||||
|
Record.push_back(D->isInlineSpecified());
|
||||||
|
Record.push_back(D->isVirtualAsWritten());
|
||||||
|
Record.push_back(D->isPure());
|
||||||
|
Record.push_back(D->hasInheritedPrototype());
|
||||||
|
Record.push_back(D->hasWrittenPrototype());
|
||||||
|
Record.push_back(D->isDeletedAsWritten());
|
||||||
|
Record.push_back(D->isTrivial());
|
||||||
|
Record.push_back(D->isDefaulted());
|
||||||
|
Record.push_back(D->isExplicitlyDefaulted());
|
||||||
|
Record.push_back(D->hasImplicitReturnZero());
|
||||||
|
Record.push_back(D->isConstexpr());
|
||||||
|
Writer.AddSourceLocation(D->getLocEnd(), Record);
|
||||||
|
|
||||||
Record.push_back(D->getTemplatedKind());
|
Record.push_back(D->getTemplatedKind());
|
||||||
switch (D->getTemplatedKind()) {
|
switch (D->getTemplatedKind()) {
|
||||||
default: llvm_unreachable("Unhandled TemplatedKind!");
|
default: llvm_unreachable("Unhandled TemplatedKind!");
|
||||||
@ -368,25 +388,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FunctionDecl's body is handled last at ASTWriterDecl::Visit,
|
|
||||||
// after everything else is written.
|
|
||||||
|
|
||||||
Record.push_back(D->getStorageClass()); // FIXME: stable encoding
|
|
||||||
Record.push_back(D->getStorageClassAsWritten());
|
|
||||||
Record.push_back(D->IsInline);
|
|
||||||
Record.push_back(D->isInlineSpecified());
|
|
||||||
Record.push_back(D->isVirtualAsWritten());
|
|
||||||
Record.push_back(D->isPure());
|
|
||||||
Record.push_back(D->hasInheritedPrototype());
|
|
||||||
Record.push_back(D->hasWrittenPrototype());
|
|
||||||
Record.push_back(D->isDeletedAsWritten());
|
|
||||||
Record.push_back(D->isTrivial());
|
|
||||||
Record.push_back(D->isDefaulted());
|
|
||||||
Record.push_back(D->isExplicitlyDefaulted());
|
|
||||||
Record.push_back(D->hasImplicitReturnZero());
|
|
||||||
Record.push_back(D->isConstexpr());
|
|
||||||
Writer.AddSourceLocation(D->getLocEnd(), Record);
|
|
||||||
|
|
||||||
Record.push_back(D->param_size());
|
Record.push_back(D->param_size());
|
||||||
for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
|
for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
|
||||||
P != PEnd; ++P)
|
P != PEnd; ++P)
|
||||||
|
@ -59,6 +59,10 @@ void consume_S4(struct S4*);
|
|||||||
typedef int T1;
|
typedef int T1;
|
||||||
typedef float T2;
|
typedef float T2;
|
||||||
|
|
||||||
|
int func0(int);
|
||||||
|
int func1(int);
|
||||||
|
int func2(int);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
template<typename T> class Vector;
|
template<typename T> class Vector;
|
||||||
|
|
||||||
|
@ -62,6 +62,13 @@ struct S4 *produce_S4(void);
|
|||||||
typedef int T1;
|
typedef int T1;
|
||||||
typedef double T2;
|
typedef double T2;
|
||||||
|
|
||||||
|
int func0(int);
|
||||||
|
int func1(int);
|
||||||
|
int func1(int);
|
||||||
|
int func1(int);
|
||||||
|
int func1(int);
|
||||||
|
static int func2(int);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
template<typename T> class Vector {
|
template<typename T> class Vector {
|
||||||
public:
|
public:
|
||||||
|
@ -61,9 +61,17 @@ void testTypedefMerge(int i, double d) {
|
|||||||
// FIXME: Typedefs aren't actually merged in the sense of other merges, because
|
// FIXME: Typedefs aren't actually merged in the sense of other merges, because
|
||||||
// we should only merge them when the types are identical.
|
// we should only merge them when the types are identical.
|
||||||
// in other file: expected-note{{candidate found by name lookup is 'T2'}}
|
// in other file: expected-note{{candidate found by name lookup is 'T2'}}
|
||||||
|
// in other file: expected-note{{candidate function}}
|
||||||
T2 *dp = &d; // expected-error{{reference to 'T2' is ambiguous}}
|
T2 *dp = &d; // expected-error{{reference to 'T2' is ambiguous}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testFuncMerge(int i) {
|
||||||
|
func0(i);
|
||||||
|
// in other file: expected-note{{candidate function}}
|
||||||
|
func1(i);
|
||||||
|
func2(i); // expected-error{{call to 'func2' is ambiguous}}
|
||||||
|
}
|
||||||
|
|
||||||
// Test redeclarations of entities in explicit submodules, to make
|
// Test redeclarations of entities in explicit submodules, to make
|
||||||
// sure we're maintaining the declaration chains even when normal name
|
// sure we're maintaining the declaration chains even when normal name
|
||||||
// lookup can't see what we're looking for.
|
// lookup can't see what we're looking for.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user