Add representation of base classes in the AST, and verify that we
don't have duplicated direct base classes.

Seriliazation of base class specifiers is not yet implemented.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@57991 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b176bc9..48b32e8 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -753,10 +753,14 @@
   // C++ Classes
   //
   /// ActOnBaseSpecifier - Parsed a base specifier
-  virtual void ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
-                                  bool Virtual, AccessSpecifier Access,
-                                  TypeTy *basetype, SourceLocation BaseLoc);
+  virtual BaseResult ActOnBaseSpecifier(DeclTy *classdecl, 
+                                        SourceRange SpecifierRange,
+                                        bool Virtual, AccessSpecifier Access,
+                                        TypeTy *basetype, SourceLocation BaseLoc);
   
+  virtual void ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases, 
+                                   unsigned NumBases);
+
   virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl,
                                      SourceLocation LBrace);
 
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index fef205c..7c4444f 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -20,6 +20,8 @@
 #include "clang/Parse/DeclSpec.h"
 #include "llvm/Support/Compiler.h"
 #include <algorithm> // for std::equal
+#include <functional>
+#include <map>
 
 using namespace clang;
 
@@ -260,23 +262,24 @@
 /// example: 
 ///    class foo : public bar, virtual private baz { 
 /// 'public bar' and 'virtual private baz' are each base-specifiers.
-void Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
-                              bool Virtual, AccessSpecifier Access,
-                              TypeTy *basetype, SourceLocation BaseLoc) {
+Sema::BaseResult 
+Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
+                         bool Virtual, AccessSpecifier Access,
+                         TypeTy *basetype, SourceLocation BaseLoc) {
   RecordDecl *Decl = (RecordDecl*)classdecl;
   QualType BaseType = Context.getTypeDeclType((TypeDecl*)basetype);
 
   // Base specifiers must be record types.
   if (!BaseType->isRecordType()) {
     Diag(BaseLoc, diag::err_base_must_be_class, SpecifierRange);
-    return;
+    return true;
   }
 
   // C++ [class.union]p1:
   //   A union shall not be used as a base class.
   if (BaseType->isUnionType()) {
     Diag(BaseLoc, diag::err_union_as_base_class, SpecifierRange);
-    return;
+    return true;
   }
 
   // C++ [class.union]p1:
@@ -284,8 +287,7 @@
   if (Decl->isUnion()) {
     Diag(Decl->getLocation(), diag::err_base_clause_on_union,
          SpecifierRange);
-    Decl->setInvalidDecl();
-    return;
+    return true;
   }
 
   // C++ [class.derived]p2:
@@ -293,14 +295,63 @@
   //   defined class.
   if (BaseType->isIncompleteType()) {
     Diag(BaseLoc, diag::err_incomplete_base_class, SpecifierRange);
-    return;
+    return true;
   }
 
-  // FIXME: C++ [class.mi]p3:
-  //   A class shall not be specified as a direct base class of a
-  //   derived class more than once.
+  // Create the base specifier.
+  CXXBaseSpecifier *BS = CXXBaseSpecifier::Create(Context, SpecifierRange, 
+                                                  Virtual, 
+                                                  BaseType->isClassType(),
+                                                  Access, BaseType);
+  return BS;
+}
 
-  // FIXME: Attach base class to the record.
+/// QualTypeOrder - Function object that provides a total ordering on
+/// QualType values.
+struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> {
+  bool operator()(QualType T1, QualType T2) {
+    return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr());
+  }
+};
+
+/// ActOnBaseSpecifiers - Attach the given base specifiers to the
+/// class, after checking whether there are any duplicate base
+/// classes.
+void Sema::ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases, 
+                               unsigned NumBases) {
+  if (NumBases == 0)
+    return;
+
+  // Used to keep track of which base types we have already seen, so
+  // that we can properly diagnose redundant direct base types. Note
+  // that the key is always the canonical type.
+  std::map<QualType, CXXBaseSpecifier*, QualTypeOrdering> KnownBaseTypes;
+
+  // Copy non-redundant base specifiers into permanent storage.
+  CXXBaseSpecifier **InBaseSpecs = (CXXBaseSpecifier **)Bases;
+  CXXBaseSpecifier **StoredBaseSpecs = new CXXBaseSpecifier* [NumBases];
+  unsigned outIdx = 0;
+  for (unsigned inIdx = 0; inIdx < NumBases; ++inIdx) {
+    QualType NewBaseType 
+      = Context.getCanonicalType(InBaseSpecs[inIdx]->getType());
+    if (KnownBaseTypes[NewBaseType]) {
+      // C++ [class.mi]p3:
+      //   A class shall not be specified as a direct base class of a
+      //   derived class more than once.
+      Diag(InBaseSpecs[inIdx]->getSourceRange().getBegin(),
+           diag::err_duplicate_base_class, 
+           KnownBaseTypes[NewBaseType]->getType().getAsString(),
+           InBaseSpecs[inIdx]->getSourceRange());
+    } else {
+      // Okay, add this new base class.
+      KnownBaseTypes[NewBaseType] = InBaseSpecs[inIdx];
+      StoredBaseSpecs[outIdx++] = InBaseSpecs[inIdx];
+    }
+  }
+
+  // Attach the remaining base class specifiers to the derived class.
+  CXXRecordDecl *Decl = (CXXRecordDecl*)ClassDecl;
+  Decl->setBases(StoredBaseSpecs, outIdx);
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index cafdf87..19bc13a 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -664,7 +664,7 @@
     // Within each iteration of the loop, we check the qualifiers to
     // determine if this still looks like a qualification
     // conversion. Then, if all is well, we unwrap one more level of
-    // pointers (FIXME: or pointers-to-members) and do it all again
+    // pointers or pointers-to-members and do it all again
     // until there are no more pointers or pointers-to-members left to
     // unwrap.
     UnwrappedAnyPointer = true;
@@ -839,7 +839,7 @@
     // Within each iteration of the loop, we check the qualifiers to
     // determine if this still looks like a qualification
     // conversion. Then, if all is well, we unwrap one more level of
-    // pointers (FIXME: or pointers-to-members) and do it all again
+    // pointers or pointers-to-members and do it all again
     // until there are no more pointers or pointers-to-members left
     // to unwrap. This essentially mimics what
     // IsQualificationConversion does, but here we're checking for a