Fix a couple of bugs, add some new cool stuff.

1. Fix a todo in Parser::ParseTag, to recover better.  On code like
   that in test/Sema/decl-invalid.c it causes us to return a single
   error instead of multiple.
2. Fix an error in Sema::ParseDeclarator, where it would crash if the
   declarator didn't have an identifier.  Instead, diagnose the problem.
3. Start adding infrastructure to track the range of locations covered
   by a declspec or declarator.  This is mostly implemented for declspec,
   but could be improved, it is missing for declarator.

Thanks to Neil for pointing out this crash.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@40482 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/AST/Decl.cpp b/AST/Decl.cpp
new file mode 100644
index 0000000..f4a346f
--- /dev/null
+++ b/AST/Decl.cpp
@@ -0,0 +1,161 @@
+//===--- Decl.cpp - Declaration AST Node Implementation -------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Decl class and subclasses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Decl.h"
+#include "clang/Lex/IdentifierTable.h"
+using namespace clang;
+
+// temporary statistics gathering
+static unsigned nFuncs = 0;
+static unsigned nBlockVars = 0;
+static unsigned nFileVars = 0;
+static unsigned nParmVars = 0;
+static unsigned nSUC = 0;
+static unsigned nEnumConst = 0;
+static unsigned nEnumDecls = 0;
+static unsigned nTypedef = 0;
+static unsigned nFieldDecls = 0;
+static bool StatSwitch = false;
+
+bool Decl::CollectingStats(bool enable) {
+  if (enable) StatSwitch = true;
+	return StatSwitch;
+}
+
+void Decl::PrintStats() {
+  fprintf(stderr, "*** Decl Stats:\n");
+  fprintf(stderr, "  %d decls total.\n", 
+	  int(nFuncs+nBlockVars+nFileVars+nParmVars+nFieldDecls+nSUC+
+	      nEnumDecls+nEnumConst+nTypedef));
+  fprintf(stderr, "    %d function decls, %d each (%d bytes)\n", 
+	  nFuncs, (int)sizeof(FunctionDecl), int(nFuncs*sizeof(FunctionDecl)));
+  fprintf(stderr, "    %d block variable decls, %d each (%d bytes)\n", 
+	  nBlockVars, (int)sizeof(BlockVarDecl), 
+	  int(nBlockVars*sizeof(BlockVarDecl)));
+  fprintf(stderr, "    %d file variable decls, %d each (%d bytes)\n", 
+	  nFileVars, (int)sizeof(FileVarDecl), 
+	  int(nFileVars*sizeof(FileVarDecl)));
+  fprintf(stderr, "    %d parameter variable decls, %d each (%d bytes)\n", 
+	  nParmVars, (int)sizeof(ParmVarDecl),
+	  int(nParmVars*sizeof(ParmVarDecl)));
+  fprintf(stderr, "    %d field decls, %d each (%d bytes)\n", 
+	  nFieldDecls, (int)sizeof(FieldDecl),
+	  int(nFieldDecls*sizeof(FieldDecl)));
+  fprintf(stderr, "    %d struct/union/class decls, %d each (%d bytes)\n", 
+	  nSUC, (int)sizeof(RecordDecl),
+	  int(nSUC*sizeof(RecordDecl)));
+  fprintf(stderr, "    %d enum decls, %d each (%d bytes)\n", 
+	  nEnumDecls, (int)sizeof(EnumDecl), 
+	  int(nEnumDecls*sizeof(EnumDecl)));
+  fprintf(stderr, "    %d enum constant decls, %d each (%d bytes)\n", 
+	  nEnumConst, (int)sizeof(EnumConstantDecl),
+	  int(nEnumConst*sizeof(EnumConstantDecl)));
+  fprintf(stderr, "    %d typedef decls, %d each (%d bytes)\n", 
+	  nTypedef, (int)sizeof(TypedefDecl),int(nTypedef*sizeof(TypedefDecl)));
+  fprintf(stderr, "Total bytes = %d\n", 
+	  int(nFuncs*sizeof(FunctionDecl)+nBlockVars*sizeof(BlockVarDecl)+
+	      nFileVars*sizeof(FileVarDecl)+nParmVars*sizeof(ParmVarDecl)+
+	      nFieldDecls*sizeof(FieldDecl)+nSUC*sizeof(RecordDecl)+
+	      nEnumDecls*sizeof(EnumDecl)+nEnumConst*sizeof(EnumConstantDecl)+
+	      nTypedef*sizeof(TypedefDecl)));
+}
+
+void Decl::addDeclKind(const Kind k) {
+  switch (k) {
+    case Typedef:
+      nTypedef++;
+      break;
+    case Function:
+      nFuncs++;
+      break;
+    case BlockVariable:
+      nBlockVars++;
+      break;
+    case FileVariable:
+      nFileVars++;
+      break;
+    case ParmVariable:
+      nParmVars++;
+      break;
+    case EnumConstant:
+      nEnumConst++;
+      break;
+    case Field:
+      nFieldDecls++;
+      break;
+    case Struct:
+    case Union:
+    case Class:
+      nSUC++;
+      break;
+    case Enum:
+      nEnumDecls++;
+      break;
+  }
+}
+
+// Out-of-line virtual method providing a home for Decl.
+Decl::~Decl() {
+}
+
+const char *Decl::getName() const {
+  if (const IdentifierInfo *II = getIdentifier())
+    return II->getName();
+  return "";
+}
+
+
+FunctionDecl::~FunctionDecl() {
+  delete[] ParamInfo;
+}
+
+unsigned FunctionDecl::getNumParams() const {
+  return cast<FunctionTypeProto>(getType().getTypePtr())->getNumArgs();
+}
+
+void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) {
+  assert(ParamInfo == 0 && "Already has param info!");
+  assert(NumParams == getNumParams() && "Parameter count mismatch!");
+  
+  // Zero params -> null pointer.
+  if (NumParams) {
+    ParamInfo = new ParmVarDecl*[NumParams];
+    memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
+  }
+}
+
+
+/// defineBody - When created, RecordDecl's correspond to a forward declared
+/// record.  This method is used to mark the decl as being defined, with the
+/// specified contents.
+void RecordDecl::defineBody(FieldDecl **members, unsigned numMembers) {
+  assert(!isDefinition() && "Cannot redefine record!");
+  setDefinition(true);
+  NumMembers = numMembers;
+  if (numMembers) {
+    Members = new FieldDecl*[numMembers];
+    memcpy(Members, members, numMembers*sizeof(Decl*));
+  }
+}
+
+FieldDecl* RecordDecl::getMember(IdentifierInfo *name) {
+  if (Members == 0 || NumMembers < 0)
+    return 0;
+	
+  // linear search. When C++ classes come along, will likely need to revisit.
+  for (int i = 0; i < NumMembers; ++i) {
+    if (Members[i]->getIdentifier() == name)
+      return Members[i];
+  }
+  return 0;
+}