Clean up handling of function redeclarations

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50021 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 6ebaac5..11e6bcf 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -403,6 +403,18 @@
 FunctionDecl::~FunctionDecl() {
   delete[] ParamInfo;
   delete Body;
+  delete PreviousDeclaration;
+}
+
+Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
+  for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) {
+    if (FD->Body) {
+      Definition = FD;
+      return FD->Body;
+    }
+  }
+
+  return 0;
 }
 
 unsigned FunctionDecl::getNumParams() const {
@@ -436,6 +448,71 @@
   return NumRequiredArgs;
 }
 
+/// AddRedeclaration - Specifies that this function declaration has been
+/// redeclared by the function declaration FD. FD must be a
+/// redeclaration of this based on the semantics of the language being
+/// translated ("compatible" function types in C, same signatures in
+/// C++). 
+void FunctionDecl::AddRedeclaration(FunctionDecl *FD) {
+  assert(FD->PreviousDeclaration == 0 && 
+         "Redeclaration already has a previous declaration!");
+
+  // Insert FD into the list of previous declarations of this
+  // function.
+  FD->PreviousDeclaration = this->PreviousDeclaration;
+  this->PreviousDeclaration = FD;
+
+  // Swap the contents of this function declaration and FD. This
+  // effectively transforms the original declaration into the most
+  // recent declaration, so that all references to this declaration
+  // remain valid (and have information from *all* declarations),
+  // while retaining all of the information about previous
+  // declarations as well.
+
+  // Swap parameters, so that the most recent parameter names and
+  // exact types (e.g., enum vs int) show up in the original
+  // declaration.
+  ParmVarDecl **thisParamInfo = this->ParamInfo;
+  this->ParamInfo = FD->ParamInfo;
+  FD->ParamInfo = thisParamInfo;
+  
+  // Swap the function body: all declarations share the same function
+  // body, but we keep track of who actually defined that function
+  // body by keeping the pointer to the body stored in that node.
+  Stmt *thisBody = this->Body;
+  this->Body = FD->Body;
+  FD->Body = thisBody;
+
+  // Swap type information: this is important because in C, later
+  // declarations can provide slightly different types (enum vs. int,
+  // for example).
+  QualType thisType = this->getType();
+  this->setType(FD->getType());
+  FD->setType(thisType);
+
+  // Swap location information: this allows us to produce diagnostics
+  // later on that reference the most recent declaration (which has
+  // the most information!) while retaining the location of previous
+  // declarations (good for "redefinition" diagnostics).
+  SourceLocation thisLocation = this->getLocation();
+  this->setLocation(FD->getLocation());
+  FD->setLocation(thisLocation);
+  
+  // Swap attributes. FD will have the union of the attributes from
+  // all previous declarations.
+  if (DeclAttrs) {
+    Attr *thisAttr = (*DeclAttrs)[this];
+    (*DeclAttrs)[this] = (*DeclAttrs)[FD];
+    (*DeclAttrs)[FD] = thisAttr;
+  }
+
+  // If any declaration is inline, the function is inline.
+  this->IsInline |= FD->IsInline;
+
+  // FIXME: Is this the right way to handle storage specifiers?
+  if (FD->SClass) this->SClass = FD->SClass;
+}
+
 //===----------------------------------------------------------------------===//
 // RecordDecl Implementation
 //===----------------------------------------------------------------------===//