Teach __builtin_offsetof to compute the offsets of members of base
classes, since we only warn (not error) on offsetof() for non-POD
types. We store the base path within the OffsetOfExpr itself, then
evaluate the offsets within the constant evaluator.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102571 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 7233518..1c2b76e 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -1414,17 +1414,41 @@
         if (*Field == MemberDecl)
           break;
       }
-      if (i < RL.getFieldCount())
-        Result += CharUnits::fromQuantity(
-                             RL.getFieldOffset(i) / Info.Ctx.getCharWidth());
-      else 
-        return false;
+      assert(i < RL.getFieldCount() && "offsetof field in wrong type");
+      Result += CharUnits::fromQuantity(
+                           RL.getFieldOffset(i) / Info.Ctx.getCharWidth());
       CurrentType = MemberDecl->getType().getNonReferenceType();
       break;
     }
         
     case OffsetOfExpr::OffsetOfNode::Identifier:
       llvm_unreachable("dependent __builtin_offsetof");
+      return false;
+        
+    case OffsetOfExpr::OffsetOfNode::Base: {
+      CXXBaseSpecifier *BaseSpec = ON.getBase();
+      if (BaseSpec->isVirtual())
+        return false;
+
+      // Find the layout of the class whose base we are looking into.
+      const RecordType *RT = CurrentType->getAs<RecordType>();
+      if (!RT) 
+        return false;
+      RecordDecl *RD = RT->getDecl();
+      const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
+
+      // Find the base class itself.
+      CurrentType = BaseSpec->getType();
+      const RecordType *BaseRT = CurrentType->getAs<RecordType>();
+      if (!BaseRT)
+        return false;
+      
+      // Add the offset to the base.
+      Result += CharUnits::fromQuantity(
+                RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl()))
+                                        / Info.Ctx.getCharWidth());
+      break;
+    }
     }
   }
   return Success(Result.getQuantity(), E);
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index b50bb0c..52f627d 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -718,7 +718,11 @@
       PrintedSomething = true;
       continue;
     }
-     
+
+    // Skip implicit base indirections.
+    if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Base)
+      continue;
+
     // Field or identifier node.
     IdentifierInfo *Id = ON.getFieldName();
     if (!Id)
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 3d528f3..d45bb2f 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -279,6 +279,10 @@
     case OffsetOfExpr::OffsetOfNode::Identifier:
       ID.AddPointer(ON.getFieldName());
       break;
+        
+    case OffsetOfExpr::OffsetOfNode::Base:
+      // These nodes are implicit, and therefore don't need profiling.
+      break;
     }
   }