[cfe-commits] r95794 - in /cfe/trunk: include/clang/Basic/DiagnosticASTKinds.td lib/AST/ASTImporter.cpp lib/Frontend/ASTMerge.cpp test/ASTMerge/Inputs/function1.c test/ASTMerge/Inputs/function2.c test/ASTMerge/function.c
Douglas Gregor
dgregor at apple.com
Wed Feb 10 11:54:32 PST 2010
Author: dgregor
Date: Wed Feb 10 13:54:31 2010
New Revision: 95794
URL: http://llvm.org/viewvc/llvm-project?rev=95794&view=rev
Log:
Implement basic support for merging function declarations across
translation units.
Added:
cfe/trunk/test/ASTMerge/Inputs/function1.c
cfe/trunk/test/ASTMerge/Inputs/function2.c
cfe/trunk/test/ASTMerge/function.c
Modified:
cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
cfe/trunk/lib/AST/ASTImporter.cpp
cfe/trunk/lib/Frontend/ASTMerge.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=95794&r1=95793&r2=95794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Wed Feb 10 13:54:31 2010
@@ -34,5 +34,8 @@
"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">;
}
Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=95794&r1=95793&r2=95794&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Wed Feb 10 13:54:31 2010
@@ -73,8 +73,17 @@
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,37 +457,156 @@
//----------------------------------------------------------------------------
// Import Declarations
//----------------------------------------------------------------------------
-Decl *ASTNodeImporter::VisitDecl(Decl *D) {
- Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
- << D->getDeclKindName();
- return 0;
-}
-
-Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
+bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC,
+ DeclContext *&LexicalDC,
+ DeclarationName &Name,
+ SourceLocation &Loc) {
// Import the context of this declaration.
- DeclContext *DC = Importer.ImportContext(D->getDeclContext());
+ DC = Importer.ImportContext(D->getDeclContext());
if (!DC)
- return 0;
-
- DeclContext *LexicalDC = DC;
+ return true;
+
+ LexicalDC = DC;
if (D->getDeclContext() != D->getLexicalDeclContext()) {
LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
if (!LexicalDC)
- return 0;
+ return true;
}
-
+
// Import the name of this declaration.
- DeclarationName Name = Importer.Import(D->getDeclName());
+ Name = Importer.Import(D->getDeclName());
if (D->getDeclName() && !Name)
- return 0;
+ 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.
- QualType T = Importer.Import(D->getType());
+ 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::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;
- // Import the location of this declaration.
- SourceLocation Loc = Importer.Import(D->getLocation());
+ // 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;
+
+ 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);
+
+ // 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?
+
+ 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;
// 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.
@@ -589,32 +717,47 @@
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.
- QualType T = Importer.Import(D->getUnderlyingType());
+ // 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;
- // Import the location of this declaration.
- SourceLocation Loc = Importer.Import(D->getLocation());
+ // 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;
+
// 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).
Modified: cfe/trunk/lib/Frontend/ASTMerge.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTMerge.cpp?rev=95794&r1=95793&r2=95794&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/ASTMerge.cpp (original)
+++ cfe/trunk/lib/Frontend/ASTMerge.cpp Wed Feb 10 13:54:31 2010
@@ -57,14 +57,21 @@
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;
Added: cfe/trunk/test/ASTMerge/Inputs/function1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/function1.c?rev=95794&view=auto
==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/function1.c (added)
+++ cfe/trunk/test/ASTMerge/Inputs/function1.c Wed Feb 10 13:54:31 2010
@@ -0,0 +1,6 @@
+void f0(int);
+void f1(int, float);
+void f2();
+void f3(void);
+void f4(int, int);
+
Added: cfe/trunk/test/ASTMerge/Inputs/function2.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/function2.c?rev=95794&view=auto
==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/function2.c (added)
+++ cfe/trunk/test/ASTMerge/Inputs/function2.c Wed Feb 10 13:54:31 2010
@@ -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);
Added: cfe/trunk/test/ASTMerge/function.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/function.c?rev=95794&view=auto
==============================================================================
--- cfe/trunk/test/ASTMerge/function.c (added)
+++ cfe/trunk/test/ASTMerge/function.c Wed Feb 10 13:54:31 2010
@@ -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
More information about the cfe-commits
mailing list