[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