Change the AST generated for offsetof a bit so that it looks like a 
normal expression, and change Evaluate and IRGen to evaluate it like a 
normal expression.  This simplifies the code significantly, and fixes 
PR3396.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65622 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index e309259..d0d14f2 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -1331,49 +1331,6 @@
   return getCond()->getIntegerConstantExprValue(C) != 0;
 }
 
-static int64_t evaluateOffsetOf(ASTContext& C, const Expr *E) {
-  if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
-    QualType Ty = ME->getBase()->getType();
-    
-    RecordDecl *RD = Ty->getAsRecordType()->getDecl();
-    const ASTRecordLayout &RL = C.getASTRecordLayout(RD);
-    if (FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
-      // FIXME: This is linear time. And the fact that we're indexing
-      // into the layout by position in the record means that we're
-      // either stuck numbering the fields in the AST or we have to keep
-      // the linear search (yuck and yuck).
-      unsigned i = 0;
-      for (RecordDecl::field_iterator Field = RD->field_begin(),
-                                   FieldEnd = RD->field_end();
-           Field != FieldEnd; (void)++Field, ++i) {
-        if (*Field == FD)
-          break;
-      }
-      
-      return RL.getFieldOffset(i) + evaluateOffsetOf(C, ME->getBase());
-    }
-  } else if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
-    const Expr *Base = ASE->getBase();
-    
-    int64_t size = C.getTypeSize(ASE->getType());
-    size *= ASE->getIdx()->getIntegerConstantExprValue(C).getSExtValue();
-    
-    return size + evaluateOffsetOf(C, Base);
-  } else if (isa<CompoundLiteralExpr>(E))
-    return 0;  
-
-  assert(0 && "Unknown offsetof subexpression!");
-  return 0;
-}
-
-int64_t UnaryOperator::evaluateOffsetOf(ASTContext& C) const
-{
-  assert(Opc == OffsetOf && "Unary operator not offsetof!");
-  
-  unsigned CharSize = C.Target.getCharWidth();
-  return ::evaluateOffsetOf(C, cast<Expr>(Val)) / CharSize;
-}
-
 void SizeOfAlignOfExpr::Destroy(ASTContext& C) {
   // Override default behavior of traversing children. If this has a type
   // operand and the type is a variable-length array, the child iteration
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 4f55f8d..68818db 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -1064,8 +1064,16 @@
 bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
   // Special case unary operators that do not need their subexpression
   // evaluated.  offsetof/sizeof/alignof are all special.
-  if (E->isOffsetOfOp())
-    return Success(E->evaluateOffsetOf(Info.Ctx), E);
+  if (E->isOffsetOfOp()) {
+    // The AST for offsetof is defined in such a way that we can just
+    // directly Evaluate it as an l-value.
+    APValue LV;
+    if (!EvaluateLValue(E->getSubExpr(), LV, Info))
+      return false;
+    if (LV.getLValueBase())
+      return false;
+    return Success(LV.getLValueOffset(), E);
+  }
 
   if (E->getOpcode() == UnaryOperator::LNot) {
     // LNot's operand isn't necessarily an integer, so we handle it specially.
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 4468c79..7e25b46 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -724,7 +724,7 @@
 }
 
 bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) {
-  if (isa<CompoundLiteralExpr>(E)) {
+  if (isa<UnaryOperator>(E)) {
     // Base case, print the type and comma.
     OS << E->getType().getAsString() << ", ";
     return true;