зеркало из https://github.com/microsoft/clang.git
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:
Родитель
4c863ef92c
Коммит
a404ea673c
|
@ -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);
|
|
@ -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
|
Загрузка…
Ссылка в новой задаче