Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini.

This change introduces a new expression node type, OffsetOfExpr, that
describes __builtin_offsetof. Previously, __builtin_offsetof was
implemented using a unary operator whose subexpression involved
various synthesized array-subscript and member-reference expressions,
which was ugly and made it very hard to instantiate as a
template. OffsetOfExpr represents the AST more faithfully, with proper
type source information and a more compact representation.

OffsetOfExpr also has support for dependent __builtin_offsetof
expressions; it can be value-dependent, but will never be
type-dependent (like sizeof or alignof). This commit introduces
template instantiation for __builtin_offsetof as well.

There are two major caveats to this patch:

  1) CodeGen cannot handle the case where __builtin_offsetof is not a
  constant expression, so it produces an error. So, to avoid
  regressing in C, we retain the old UnaryOperator-based
  __builtin_offsetof implementation in C while using the shiny new
  OffsetOfExpr implementation in C++. The old implementation can go
  away once we have proper CodeGen support for this case, which we
  expect won't cause much trouble in C++.

  2) __builtin_offsetof doesn't work well with non-POD class types,
  particularly when the designated field is found within a base
  class. I will address this in a subsequent patch.

Fixes PR5880 and a bunch of assertions when building Boost.Python
tests. 



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102542 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index a52cf6f..7233518 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -16,7 +16,9 @@
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeLoc.h"
 #include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/Expr.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/SmallString.h"
@@ -228,7 +230,7 @@
   APValue VisitStmt(Stmt *S) {
     return APValue();
   }
-
+  
   APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
   APValue VisitDeclRefExpr(DeclRefExpr *E);
   APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E); }
@@ -828,6 +830,7 @@
 
   bool VisitCallExpr(CallExpr *E);
   bool VisitBinaryOperator(const BinaryOperator *E);
+  bool VisitOffsetOfExpr(const OffsetOfExpr *E);
   bool VisitUnaryOperator(const UnaryOperator *E);
   bool VisitConditionalOperator(const ConditionalOperator *E);
 
@@ -1372,6 +1375,61 @@
   return Success(Info.Ctx.getTypeSizeInChars(SrcTy).getQuantity(), E);
 }
 
+bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
+  CharUnits Result;
+  unsigned n = E->getNumComponents();
+  OffsetOfExpr* OOE = const_cast<OffsetOfExpr*>(E);
+  if (n == 0)
+    return false;
+  QualType CurrentType = E->getTypeSourceInfo()->getType();
+  for (unsigned i = 0; i != n; ++i) {
+    OffsetOfExpr::OffsetOfNode ON = OOE->getComponent(i);
+    switch (ON.getKind()) {
+    case OffsetOfExpr::OffsetOfNode::Array: {
+      Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex());
+      APSInt IdxResult;
+      if (!EvaluateInteger(Idx, IdxResult, Info))
+        return false;
+      const ArrayType *AT = Info.Ctx.getAsArrayType(CurrentType);
+      if (!AT)
+        return false;
+      CurrentType = AT->getElementType();
+      CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType);
+      Result += IdxResult.getSExtValue() * ElementSize;
+        break;
+    }
+        
+    case OffsetOfExpr::OffsetOfNode::Field: {
+      FieldDecl *MemberDecl = ON.getField();
+      const RecordType *RT = CurrentType->getAs<RecordType>();
+      if (!RT) 
+        return false;
+      RecordDecl *RD = RT->getDecl();
+      const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
+      unsigned i = 0;
+      // FIXME: It would be nice if we didn't have to loop here!
+      for (RecordDecl::field_iterator Field = RD->field_begin(),
+                                      FieldEnd = RD->field_end();
+           Field != FieldEnd; (void)++Field, ++i) {
+        if (*Field == MemberDecl)
+          break;
+      }
+      if (i < RL.getFieldCount())
+        Result += CharUnits::fromQuantity(
+                             RL.getFieldOffset(i) / Info.Ctx.getCharWidth());
+      else 
+        return false;
+      CurrentType = MemberDecl->getType().getNonReferenceType();
+      break;
+    }
+        
+    case OffsetOfExpr::OffsetOfNode::Identifier:
+      llvm_unreachable("dependent __builtin_offsetof");
+    }
+  }
+  return Success(Result.getQuantity(), E);
+}
+
 bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
   // Special case unary operators that do not need their subexpression
   // evaluated.  offsetof/sizeof/alignof are all special.
@@ -1380,12 +1438,12 @@
     // directly Evaluate it as an l-value.
     APValue LV;
     if (!EvaluateLValue(E->getSubExpr(), LV, Info))
-      return false;
+        return false;
     if (LV.getLValueBase())
-      return false;
+        return false;
     return Success(LV.getLValueOffset().getQuantity(), E);
   }
-
+    
   if (E->getOpcode() == UnaryOperator::LNot) {
     // LNot's operand isn't necessarily an integer, so we handle it specially.
     bool bres;