Implement basic support for merging function declarations across

translation units.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95794 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2010-02-10 19:54:31 +00:00
Родитель 4c863ef92c
Коммит a404ea673c
6 изменённых файлов: 213 добавлений и 39 удалений

Просмотреть файл

@ -34,5 +34,8 @@ def err_odr_variable_multiple_def : Error<
"external variable %0 defined in multiple translation units">;
def note_odr_value_here : Note<"declared here with type %0">;
def note_odr_defined_here : Note<"also defined here">;
def err_odr_function_type_inconsistent : Error<
"external function %0 declared with incompatible types in different "
"translation units (%1 vs. %2)">;
def err_unsupported_ast_node: Error<"cannot import unsupported AST node %0">;
}

Просмотреть файл

@ -73,8 +73,17 @@ namespace {
QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T);
// Importing declarations
bool ImportDeclParts(NamedDecl *D, DeclContext *&DC,
DeclContext *&LexicalDC, DeclarationName &Name,
SourceLocation &Loc);
bool ImportDeclParts(DeclaratorDecl *D,
DeclContext *&DC, DeclContext *&LexicalDC,
DeclarationName &Name, SourceLocation &Loc,
QualType &T);
Decl *VisitDecl(Decl *D);
Decl *VisitFunctionDecl(FunctionDecl *D);
Decl *VisitVarDecl(VarDecl *D);
Decl *VisitParmVarDecl(ParmVarDecl *D);
Decl *VisitTypedefDecl(TypedefDecl *D);
};
}
@ -448,38 +457,157 @@ QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) {
//----------------------------------------------------------------------------
// Import Declarations
//----------------------------------------------------------------------------
bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC,
DeclContext *&LexicalDC,
DeclarationName &Name,
SourceLocation &Loc) {
// Import the context of this declaration.
DC = Importer.ImportContext(D->getDeclContext());
if (!DC)
return true;
LexicalDC = DC;
if (D->getDeclContext() != D->getLexicalDeclContext()) {
LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
if (!LexicalDC)
return true;
}
// Import the name of this declaration.
Name = Importer.Import(D->getDeclName());
if (D->getDeclName() && !Name)
return true;
// Import the location of this declaration.
Loc = Importer.Import(D->getLocation());
return false;
}
bool ASTNodeImporter::ImportDeclParts(DeclaratorDecl *D,
DeclContext *&DC,
DeclContext *&LexicalDC,
DeclarationName &Name,
SourceLocation &Loc,
QualType &T) {
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
return true;
// Import the type of this declaration.
T = Importer.Import(D->getType());
if (T.isNull())
return true;
return false;
}
Decl *ASTNodeImporter::VisitDecl(Decl *D) {
Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
<< D->getDeclKindName();
return 0;
}
Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
// Import the context of this declaration.
DeclContext *DC = Importer.ImportContext(D->getDeclContext());
if (!DC)
Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Import the major distinguishing characteristics of this function.
DeclContext *DC, *LexicalDC;
DeclarationName Name;
QualType T;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc, T))
return 0;
// Try to find a function in our own ("to") context with the same name, same
// type, and in the same context as the function we're importing.
if (!LexicalDC->isFunctionOrMethod()) {
llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
for (DeclContext::lookup_result Lookup = DC->lookup(Name);
Lookup.first != Lookup.second;
++Lookup.first) {
if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
continue;
DeclContext *LexicalDC = DC;
if (D->getDeclContext() != D->getLexicalDeclContext()) {
LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
if (!LexicalDC)
return 0;
if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(*Lookup.first)) {
if (isExternalLinkage(FoundFunction->getLinkage()) &&
isExternalLinkage(D->getLinkage())) {
if (Importer.getToContext().typesAreCompatible(T,
FoundFunction->getType())) {
// FIXME: Actually try to merge the body and other attributes.
Importer.getImportedDecls()[D] = FoundFunction;
return FoundFunction;
}
// FIXME: Check for overloading more carefully, e.g., by boosting
// Sema::IsOverload out to the AST library.
// Function overloading is okay in C++.
if (Importer.getToContext().getLangOptions().CPlusPlus)
continue;
// Complain about inconsistent function types.
Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent)
<< Name << T << FoundFunction->getType();
Importer.ToDiag(FoundFunction->getLocation(),
diag::note_odr_value_here)
<< FoundFunction->getType();
}
}
ConflictingDecls.push_back(*Lookup.first);
}
if (!ConflictingDecls.empty()) {
Name = Importer.HandleNameConflict(Name, DC, IDNS,
ConflictingDecls.data(),
ConflictingDecls.size());
if (!Name)
return 0;
}
}
// Import the function parameters.
llvm::SmallVector<ParmVarDecl *, 8> Parameters;
for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end();
P != PEnd; ++P) {
ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(*P));
if (!ToP)
return 0;
Parameters.push_back(ToP);
}
// Create the imported function.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
FunctionDecl *ToFunction
= FunctionDecl::Create(Importer.getToContext(), DC, Loc,
Name, T, TInfo, D->getStorageClass(),
D->isInlineSpecified(),
D->hasWrittenPrototype());
ToFunction->setLexicalDeclContext(LexicalDC);
Importer.getImportedDecls()[D] = ToFunction;
LexicalDC->addDecl(ToFunction);
// Import the name of this declaration.
DeclarationName Name = Importer.Import(D->getDeclName());
if (D->getDeclName() && !Name)
return 0;
// Set the parameters.
for (unsigned I = 0, N = Parameters.size(); I != N; ++I) {
Parameters[I]->setOwningFunction(ToFunction);
ToFunction->addDecl(Parameters[I]);
}
ToFunction->setParams(Importer.getToContext(),
Parameters.data(), Parameters.size());
// FIXME: Other bits to merge?
// Import the type of this declaration.
QualType T = Importer.Import(D->getType());
if (T.isNull())
return ToFunction;
}
Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
// Import the major distinguishing characteristics of a variable.
DeclContext *DC, *LexicalDC;
DeclarationName Name;
QualType T;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc, T))
return 0;
// Import the location of this declaration.
SourceLocation Loc = Importer.Import(D->getLocation());
// Try to find a variable in our own ("to") context with the same name and
// in the same context as the variable we're importing.
if (D->isFileVarDecl()) {
@ -589,32 +717,47 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
return ToVar;
}
Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
// Import the context of this declaration.
DeclContext *DC = Importer.ImportContext(D->getDeclContext());
if (!DC)
return 0;
DeclContext *LexicalDC = DC;
if (D->getDeclContext() != D->getLexicalDeclContext()) {
LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
if (!LexicalDC)
return 0;
}
Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
// Parameters are created in the translation unit's context, then moved
// into the function declaration's context afterward.
DeclContext *DC = Importer.getToContext().getTranslationUnitDecl();
// Import the name of this declaration.
DeclarationName Name = Importer.Import(D->getDeclName());
if (D->getDeclName() && !Name)
return 0;
// Import the type of this declaration.
// Import the location of this declaration.
SourceLocation Loc = Importer.Import(D->getLocation());
// Import the parameter's type.
QualType T = Importer.Import(D->getType());
if (T.isNull())
return 0;
// Create the imported parameter.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC,
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getStorageClass(),
/*FIXME: Default argument*/ 0);
Importer.getImportedDecls()[D] = ToParm;
return ToParm;
}
Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
// Import the major distinguishing characteristics of this typedef.
DeclContext *DC, *LexicalDC;
DeclarationName Name;
SourceLocation Loc;
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
return 0;
// Import the underlying type of this typedef;
QualType T = Importer.Import(D->getUnderlyingType());
if (T.isNull())
return 0;
// Import the location of this declaration.
SourceLocation Loc = Importer.Import(D->getLocation());
// If this typedef is not in block scope, determine whether we've
// seen a typedef with the same name (that we can merge with) or any
// other entity by that name (which name lookup could conflict with).

Просмотреть файл

@ -57,14 +57,21 @@ void ASTMergeAction::ExecuteAction() {
for (DeclContext::decl_iterator D = TU->decls_begin(),
DEnd = TU->decls_end();
D != DEnd; ++D) {
// FIXME: We only merge variables whose names start with x. Why
// would anyone want anything else?
if (VarDecl *VD = dyn_cast<VarDecl>(*D))
// FIXME: We only merge variables whose names start with x and functions
// whose names start with 'f'. Why would anyone want anything else?
if (VarDecl *VD = dyn_cast<VarDecl>(*D)) {
if (VD->getIdentifier() &&
*VD->getIdentifier()->getNameStart() == 'x') {
Decl *Merged = Importer.Import(VD);
(void)Merged;
}
} else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) {
if (FD->getIdentifier() &&
*FD->getIdentifier()->getNameStart() == 'f') {
Decl *Merged = Importer.Import(FD);
(void)Merged;
}
}
}
delete Unit;

Просмотреть файл

@ -0,0 +1,6 @@
void f0(int);
void f1(int, float);
void f2();
void f3(void);
void f4(int, int);

Просмотреть файл

@ -0,0 +1,6 @@
typedef int Int;
void f0(Int);
void f1(Int, double);
void f2(int, int);
void f3(int);
static void f4(float, float);

9
test/ASTMerge/function.c Normal file
Просмотреть файл

@ -0,0 +1,9 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/function1.c
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/function2.c
// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
// CHECK: function2.c:3:6: error: external function 'f1' declared with incompatible types in different translation units ('void (Int, double)' vs. 'void (int, float)')
// CHECK: function1.c:2:6: note: declared here with type 'void (int, float)'
// CHECK: function2.c:5:6: error: external function 'f3' declared with incompatible types in different translation units ('void (int)' vs. 'void (void)')
// CHECK: function1.c:4:6: note: declared here with type 'void (void)'
// CHECK: 4 diagnostics generated