Index: include/clang/Frontend/StmtXML.def
===================================================================
--- include/clang/Frontend/StmtXML.def	(revisione 102050)
+++ include/clang/Frontend/StmtXML.def	(copia locale)
@@ -254,7 +254,6 @@
     ENUM_XML(UnaryOperator::Real,    "__real")
     ENUM_XML(UnaryOperator::Imag,    "__imag")
     ENUM_XML(UnaryOperator::Extension, "__extension__")
-    ENUM_XML(UnaryOperator::OffsetOf,  "__builtin_offsetof")
   END_ENUM_XML
   SUB_NODE_XML(Expr)                                    // expr
 END_NODE_XML
@@ -311,6 +310,13 @@
   SUB_NODE_XML(Expr)                                    // expr3
 END_NODE_XML
 
+NODE_XML(OffsetOfExpr, "OffsetOfExpr")                  // offsetof(basetype, components)
+  ATTRIBUTE_FILE_LOCATION_XML
+  TYPE_ATTRIBUTE_XML(getTypeSourceInfo()->getType())
+  ATTRIBUTE_XML(getNumComponents(), "num_components")
+  SUB_NODE_SEQUENCE_XML(OffsetOfExpr::OffsetOfNode)
+END_NODE_XML
+
 NODE_XML(SizeOfAlignOfExpr, "SizeOfAlignOfExpr")        // sizeof(expr) or alignof(expr)
   ATTRIBUTE_FILE_LOCATION_XML
   TYPE_ATTRIBUTE_XML(getType())
Index: include/clang/Checker/PathSensitive/GRExprEngine.h
===================================================================
--- include/clang/Checker/PathSensitive/GRExprEngine.h	(revisione 102050)
+++ include/clang/Checker/PathSensitive/GRExprEngine.h	(copia locale)
@@ -342,6 +342,10 @@
 
   /// VisitReturnStmt - Transfer function logic for return statements.
   void VisitReturnStmt(ReturnStmt* R, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+  
+  /// VisitOffsetOfExpr - Transfer function for offsetof.
+  void VisitOffsetOfExpr(OffsetOfExpr* Ex, ExplodedNode* Pred,
+                         ExplodedNodeSet& Dst);
 
   /// VisitSizeOfAlignOfExpr - Transfer function for sizeof.
   void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ExplodedNode* Pred,
Index: include/clang/AST/StmtVisitor.h
===================================================================
--- include/clang/AST/StmtVisitor.h	(revisione 102050)
+++ include/clang/AST/StmtVisitor.h	(copia locale)
@@ -98,7 +98,6 @@
       case UnaryOperator::Real:         DISPATCH(UnaryReal,      UnaryOperator);
       case UnaryOperator::Imag:         DISPATCH(UnaryImag,      UnaryOperator);
       case UnaryOperator::Extension:    DISPATCH(UnaryExtension, UnaryOperator);
-      case UnaryOperator::OffsetOf:     DISPATCH(UnaryOffsetOf,  UnaryOperator);
       }
     }
 
@@ -163,7 +162,7 @@
   UNARYOP_FALLBACK(Plus)      UNARYOP_FALLBACK(Minus)
   UNARYOP_FALLBACK(Not)       UNARYOP_FALLBACK(LNot)
   UNARYOP_FALLBACK(Real)      UNARYOP_FALLBACK(Imag)
-  UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(OffsetOf)
+  UNARYOP_FALLBACK(Extension)
 #undef UNARYOP_FALLBACK
 
   // Base case, ignore it. :)
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h	(revisione 102050)
+++ include/clang/AST/Expr.h	(copia locale)
@@ -218,7 +218,7 @@
   }
   /// isConstantInitializer - Returns true if this expression is a constant
   /// initializer, which can be emitted at compile-time.
-  bool isConstantInitializer(ASTContext &Ctx) const;
+  bool isConstantInitializer(ASTContext &Ctx) const; 
 
   /// EvalResult is a struct with detailed info about an evaluated expression.
   struct EvalResult {
@@ -907,10 +907,6 @@
 ///   applied to a non-complex value, the former returns its operand and the
 ///   later returns zero in the type of the operand.
 ///
-/// __builtin_offsetof(type, a.b[10]) is represented as a unary operator whose
-///   subexpression is a compound literal with the various MemberExpr and
-///   ArraySubscriptExpr's applied to it.
-///
 class UnaryOperator : public Expr {
 public:
   // Note that additions to this should also update the StmtVisitor class.
@@ -921,8 +917,7 @@
     Plus, Minus,      // [C99 6.5.3.3] Unary arithmetic operators.
     Not, LNot,        // [C99 6.5.3.3] Unary arithmetic operators.
     Real, Imag,       // "__real expr"/"__imag expr" Extension.
-    Extension,        // __extension__ marker.
-    OffsetOf          // __builtin_offsetof
+    Extension         // __extension__ marker.
   };
 private:
   Stmt *Val;
@@ -932,7 +927,7 @@
 
   UnaryOperator(Expr *input, Opcode opc, QualType type, SourceLocation l)
     : Expr(UnaryOperatorClass, type,
-           input->isTypeDependent() && opc != OffsetOf,
+           input->isTypeDependent(),
            input->isValueDependent()),
       Val(input), Opc(opc), Loc(l) {}
 
@@ -964,7 +959,6 @@
   bool isPostfix() const { return isPostfix(Opc); }
   bool isIncrementOp() const {return Opc==PreInc || Opc==PostInc; }
   bool isIncrementDecrementOp() const { return Opc>=PostInc && Opc<=PreDec; }
-  bool isOffsetOfOp() const { return Opc == OffsetOf; }
   static bool isArithmeticOp(Opcode Op) { return Op >= Plus && Op <= LNot; }
   bool isArithmeticOp() const { return isArithmeticOp(Opc); }
 
@@ -998,6 +992,127 @@
   virtual child_iterator child_end();
 };
 
+/// OffsetOfExpr - [C99 7.17] - This represents an expression of the form
+/// offsetof(record-type, member-designator). For example, given:
+/// @code
+/// struct S {
+///   float f;
+///   double d;    
+/// };
+/// struct T {
+///   int i;
+///   struct S s[10];
+/// };
+/// @endcode
+/// we can represent and evaluate the expression @c offsetof(struct T, s[2].d). 
+
+class OffsetOfExpr : public Expr {
+
+public:
+  // __builtin_offsetof(type, identifier(.identifier|[expr])*)
+  // FIXME: Type-dependent case ignored.
+  struct OffsetOfNode {
+    SourceLocation LocStart, LocEnd;
+    bool isBrackets;  // true if [expr], false if .ident
+    union {
+      FieldDecl *MemberDecl;
+      unsigned ExprIndex; // Index of Expr* in the corresponding array.
+    } U;
+  };
+
+private:
+  
+  SourceLocation LocStart, LocEnd; 
+  // Base type;
+  TypeSourceInfo *TSInfo;
+  // Number of sub-components (i.e. instances of OffsetOfNode).
+  unsigned NumComps;
+  // Number of sub-expressions (i.e. array subscript expressions).
+  unsigned NumExprs;
+  
+  OffsetOfExpr(ASTContext &C, QualType type, 
+               SourceLocation locStart, TypeSourceInfo *tsi,
+               OffsetOfNode* compsPtr, unsigned numComps, 
+                      Expr** exprsPtr, unsigned numExprs);
+
+  explicit OffsetOfExpr(unsigned numComps, unsigned numExprs)
+    : Expr(OffsetOfExprClass, EmptyShell()),
+      TSInfo(0), NumComps(numComps), NumExprs(numExprs) {}  
+
+public:
+  
+  static OffsetOfExpr *Create(ASTContext &C, QualType type, 
+                              SourceLocation locStart, TypeSourceInfo *tsi, 
+                              OffsetOfNode* compsPtr, unsigned numComps, 
+                                     Expr** exprsPtr, unsigned numExprs);
+
+  static OffsetOfExpr *CreateEmpty(ASTContext &C, 
+                                   unsigned NumComps, unsigned NumExprs);
+
+  /// getOperatorLoc - Return the location of the operator.
+  SourceLocation getOperatorLoc() const { return LocStart; }
+  void setOperatorLoc(SourceLocation L) { LocStart = L; }
+
+  TypeSourceInfo *getTypeSourceInfo() const {
+    return TSInfo;
+  }
+  void setTypeSourceInfo(TypeSourceInfo *tsi) {
+    TSInfo = tsi;
+  }
+  
+  OffsetOfNode getComponent(unsigned Idx) {
+    assert(Idx < NumComps && "Subscript out of range");
+    char* Ptr = static_cast<char*>(static_cast<void *>(this));
+    Ptr += sizeof(OffsetOfExpr);
+    return reinterpret_cast<OffsetOfNode*>(reinterpret_cast<void**>(Ptr))[Idx];
+  }
+
+  void setComponent(unsigned Idx, OffsetOfNode ON) {
+    assert(Idx < NumComps && "Subscript out of range");
+    char* Ptr = static_cast<char*>(static_cast<void *>(this));
+    Ptr += sizeof(OffsetOfExpr);
+    reinterpret_cast<OffsetOfNode*>(reinterpret_cast<void**>(Ptr))[Idx] = ON;
+  }
+  
+  unsigned getNumComponents() const {
+    return NumComps;
+  }
+
+  Expr* getIndexExpr(unsigned Idx) {
+    assert(Idx < NumExprs && "Subscript out of range");
+    char* Ptr = static_cast<char*>(static_cast<void *>(this));
+    Ptr += sizeof(OffsetOfExpr) + sizeof(OffsetOfNode) * (NumComps + 1);
+    return reinterpret_cast<Expr**>(reinterpret_cast<void**>(Ptr))[Idx];
+  }
+
+  void setIndexExpr(unsigned Idx, Expr* E) {
+    assert(Idx < NumComps && "Subscript out of range");
+    char* Ptr = static_cast<char*>(static_cast<void *>(this));
+    Ptr += sizeof(OffsetOfExpr) + sizeof(OffsetOfNode) * (NumComps + 1);
+    reinterpret_cast<Expr**>(reinterpret_cast<void**>(Ptr))[Idx] = E;
+  }
+  
+  unsigned getNumExpressions() const {
+    return NumExprs;
+  }
+
+  virtual SourceRange getSourceRange() const {
+    return SourceRange(LocStart, LocEnd);
+  }
+
+  virtual SourceLocation getExprLoc() const { return LocStart; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == OffsetOfExprClass;
+  }
+
+  static bool classof(const OffsetOfExpr *) { return true; }
+
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();
+};
+
 /// SizeOfAlignOfExpr - [C99 6.5.3.4] - This is for sizeof/alignof, both of
 /// types and expressions.
 class SizeOfAlignOfExpr : public Expr {
Index: include/clang/AST/StmtNodes.def
===================================================================
--- include/clang/AST/StmtNodes.def	(revisione 102050)
+++ include/clang/AST/StmtNodes.def	(copia locale)
@@ -78,6 +78,7 @@
 EXPR(CharacterLiteral      , Expr)
 EXPR(ParenExpr             , Expr)
 EXPR(UnaryOperator         , Expr)
+EXPR(OffsetOfExpr          , Expr)
 EXPR(SizeOfAlignOfExpr     , Expr)
 EXPR(ArraySubscriptExpr    , Expr)
 EXPR(CallExpr              , Expr)
Index: tools/CIndex/CXCursor.cpp
===================================================================
--- tools/CIndex/CXCursor.cpp	(revisione 102050)
+++ tools/CIndex/CXCursor.cpp	(copia locale)
@@ -140,7 +140,8 @@
   case Stmt::StringLiteralClass:         
   case Stmt::CharacterLiteralClass:      
   case Stmt::ParenExprClass:             
-  case Stmt::UnaryOperatorClass:         
+  case Stmt::UnaryOperatorClass:
+  case Stmt::OffsetOfExprClass:         
   case Stmt::SizeOfAlignOfExprClass:     
   case Stmt::ArraySubscriptExprClass:    
   case Stmt::BinaryOperatorClass:        
Index: lib/Frontend/StmtXML.cpp
===================================================================
--- lib/Frontend/StmtXML.cpp	(revisione 102050)
+++ lib/Frontend/StmtXML.cpp	(copia locale)
@@ -125,6 +125,7 @@
     void VisitFloatingLiteral(FloatingLiteral *Node);
     void VisitStringLiteral(StringLiteral *Str);
     void VisitUnaryOperator(UnaryOperator *Node);
+    void VisitOffsetOfExpr(OffsetOfExpr *Node);
     void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node);
     void VisitMemberExpr(MemberExpr *Node);
     void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
@@ -260,7 +261,6 @@
   case UnaryOperator::Real:    return "__real";
   case UnaryOperator::Imag:    return "__imag";
   case UnaryOperator::Extension: return "__extension__";
-  case UnaryOperator::OffsetOf: return "__builtin_offsetof";
   }
 }
 
@@ -308,6 +308,10 @@
   Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode()));
 }
 
+void StmtXML::OffsetOfExpr(OffsetOfExpr *Node) {
+  DumpExpr(Node);
+}
+
 void StmtXML::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
   DumpExpr(Node);
   Doc.addAttribute("is_sizeof", Node->isSizeOf() ? "sizeof" : "alignof");
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h	(revisione 102050)
+++ lib/Sema/TreeTransform.h	(copia locale)
@@ -3830,6 +3830,13 @@
 
 template<typename Derived>
 Sema::OwningExprResult
+TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) {
+  // FIXME: Add template-instantiation logic.
+  return SemaRef.Owned(new (SemaRef.Context) OffsetOfExpr(*E));
+}
+
+template<typename Derived>
+Sema::OwningExprResult
 TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
   if (E->isArgumentType()) {
     TypeSourceInfo *OldT = E->getArgumentTypeInfo();
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp	(revisione 102050)
+++ lib/Sema/SemaChecking.cpp	(copia locale)
@@ -1942,13 +1942,16 @@
     // Operations with opaque sources are black-listed.
     case UnaryOperator::Deref:
     case UnaryOperator::AddrOf: // should be impossible
-    case UnaryOperator::OffsetOf:
       return IntRange::forType(C, E->getType());
 
     default:
       return GetExprRange(C, UO->getSubExpr(), MaxWidth);
     }
   }
+  
+  if (dyn_cast<OffsetOfExpr>(E)) {
+    IntRange::forType(C, E->getType());
+  }
 
   FieldDecl *BitField = E->getBitField();
   if (BitField) {
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp	(revisione 102050)
+++ lib/Sema/SemaExpr.cpp	(copia locale)
@@ -18,6 +18,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
 #include "clang/Basic/PartialDiagnostic.h"
@@ -6410,9 +6411,6 @@
   Expr *Input = (Expr *)InputArg.get();
   QualType resultType;
   switch (Opc) {
-  case UnaryOperator::OffsetOf:
-    assert(false && "Invalid unary operator");
-    break;
 
   case UnaryOperator::PreInc:
   case UnaryOperator::PreDec:
@@ -6578,12 +6576,12 @@
                                                   OffsetOfComponent *CompPtr,
                                                   unsigned NumComponents,
                                                   SourceLocation RPLoc) {
-  // FIXME: This function leaks all expressions in the offset components on
-  // error.
-  // FIXME: Preserve type source info.
-  QualType ArgTy = GetTypeFromParser(argty);
-  assert(!ArgTy.isNull() && "Missing type argument!");
 
+  TypeSourceInfo *ArgTInfo;
+  QualType ArgTy = GetTypeFromParser(argty, &ArgTInfo);
+  if (ArgTy.isNull())
+    return ExprError();
+
   bool Dependent = ArgTy->isDependentType();
 
   // We must have at least one component that refers to the type, and the first
@@ -6594,14 +6592,11 @@
 
   // FIXME: Type must be complete per C99 7.17p3 because a declaring a variable
   // with an incomplete type would be illegal.
+  
+  llvm::SmallVector<OffsetOfExpr::OffsetOfNode, 4> Comps;
+  llvm::SmallVector<Expr*, 4> Exprs;
+  unsigned numExprs = 0;
 
-  // Otherwise, create a null pointer as the base, and iteratively process
-  // the offsetof designators.
-  QualType ArgTyPtr = Context.getPointerType(ArgTy);
-  Expr* Res = new (Context) ImplicitValueInitExpr(ArgTyPtr);
-  Res = new (Context) UnaryOperator(Res, UnaryOperator::Deref,
-                                    ArgTy, SourceLocation());
-
   // offsetof with non-identifier designators (e.g. "offsetof(x, a.b[c])") are a
   // GCC extension, diagnose them.
   // FIXME: This diagnostic isn't actually visible because the location is in
@@ -6612,88 +6607,91 @@
 
   if (!Dependent) {
     bool DidWarnAboutNonPOD = false;
+    QualType CurrentType = ArgTy;
 
-    if (RequireCompleteType(TypeLoc, Res->getType(),
+    if (RequireCompleteType(TypeLoc, CurrentType,
                             diag::err_offsetof_incomplete_type))
       return ExprError();
-
-    // FIXME: Dependent case loses a lot of information here. And probably
-    // leaks like a sieve.
+    
     for (unsigned i = 0; i != NumComponents; ++i) {
       const OffsetOfComponent &OC = CompPtr[i];
+      OffsetOfExpr::OffsetOfNode ON;
       if (OC.isBrackets) {
         // Offset of an array sub-field.  TODO: Should we allow vector elements?
-        const ArrayType *AT = Context.getAsArrayType(Res->getType());
-        if (!AT) {
-          Res->Destroy(Context);
+        const ArrayType *AT = Context.getAsArrayType(CurrentType);
+        if(!AT)
           return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type)
-            << Res->getType());
-        }
+            << CurrentType);
 
         // FIXME: C++: Verify that operator[] isn't overloaded.
 
-        // Promote the array so it looks more like a normal array subscript
-        // expression.
-        DefaultFunctionArrayLvalueConversion(Res);
-
         // C99 6.5.2.1p1
         Expr *Idx = static_cast<Expr*>(OC.U.E);
-        // FIXME: Leaks Res
         if (!Idx->isTypeDependent() && !Idx->getType()->isIntegerType())
           return ExprError(Diag(Idx->getLocStart(),
                                 diag::err_typecheck_subscript_not_integer)
-            << Idx->getSourceRange());
-
-        Res = new (Context) ArraySubscriptExpr(Res, Idx, AT->getElementType(),
-                                               OC.LocEnd);
+                             << Idx->getSourceRange());
+        CurrentType = AT->getElementType();
+        ON.isBrackets = true;
+        ON.U.ExprIndex = numExprs;
+        ON.LocStart = OC.LocStart;
+        ON.LocEnd = OC.LocEnd;
+        Comps.push_back(ON);
+        Exprs.push_back(Idx);
+        ++numExprs;
         continue;
       }
-
-      const RecordType *RC = Res->getType()->getAs<RecordType>();
-      if (!RC) {
-        Res->Destroy(Context);
+      ON.isBrackets = false;
+      const RecordType *RC = CurrentType->getAs<RecordType>();
+      if (!RC) 
         return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
-          << Res->getType());
-      }
-
-      // Get the decl corresponding to this.
+          << CurrentType);
       RecordDecl *RD = RC->getDecl();
       if (CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) {
         if (!CRD->isPOD() && !DidWarnAboutNonPOD &&
-            DiagRuntimeBehavior(BuiltinLoc,
-                                PDiag(diag::warn_offsetof_non_pod_type)
-                                  << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
-                                  << Res->getType()))
+          DiagRuntimeBehavior(BuiltinLoc,
+                              PDiag(diag::warn_offsetof_non_pod_type)
+                                << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
+                                << CurrentType))
           DidWarnAboutNonPOD = true;
       }
-
       LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName);
       LookupQualifiedName(R, RD);
-
       FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>();
-      // FIXME: Leaks Res
       if (!MemberDecl)
         return ExprError(Diag(BuiltinLoc, diag::err_no_member)
-         << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd));
+          << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd));
 
       // FIXME: C++: Verify that MemberDecl isn't a static field.
       // FIXME: Verify that MemberDecl isn't a bitfield.
+
       if (cast<RecordDecl>(MemberDecl->getDeclContext())->isAnonymousStructOrUnion()) {
-        Res = BuildAnonymousStructUnionMemberReference(
-            OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs<Expr>();
-      } else {
-        PerformObjectMemberConversion(Res, /*Qualifier=*/0,
-                                      *R.begin(), MemberDecl);
-        // MemberDecl->getType() doesn't get the right qualifiers, but it
-        // doesn't matter here.
-        Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd,
-                MemberDecl->getType().getNonReferenceType());
+        llvm::SmallVector<FieldDecl*, 4> Path;
+        BuildAnonymousStructUnionMemberPath(MemberDecl, Path);
+        unsigned n = Path.size();
+        for (int j = n - 1; j > -1; --j) {
+          FieldDecl *CurrentField = Path[j];
+          ON.U.MemberDecl = CurrentField;
+          ON.LocStart = CurrentField->getLocStart();
+          ON.LocEnd = CurrentField->getLocEnd();
+          Comps.push_back(ON);
+        }
       }
+      else {
+        ON.U.MemberDecl = MemberDecl;
+        ON.LocStart = OC.LocStart;
+        ON.LocEnd = OC.LocEnd;
+        Comps.push_back(ON);
+      }
+      CurrentType = MemberDecl->getType().getNonReferenceType(); 
     }
   }
-
-  return Owned(new (Context) UnaryOperator(Res, UnaryOperator::OffsetOf,
-                                           Context.getSizeType(), BuiltinLoc));
+  unsigned numComps = Comps.size();
+  Comps.push_back(OffsetOfExpr::OffsetOfNode());
+  Exprs.push_back(0);
+  return Owned(OffsetOfExpr::Create(Context, Context.getSizeType(), BuiltinLoc, 
+                                    ArgTInfo, &Comps[0], numComps, 
+                                    &Exprs[0], numExprs));
 }
 
 
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp	(revisione 102050)
+++ lib/AST/ExprConstant.cpp	(copia locale)
@@ -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,20 +1375,55 @@
   return Success(Info.Ctx.getTypeSizeInChars(SrcTy).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.
-  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))
+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);
+    if (ON.isBrackets) {
+      Expr *Idx = OOE->getIndexExpr(ON.U.ExprIndex);
+      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;
+      continue;
+    }
+    FieldDecl *MemberDecl = ON.U.MemberDecl;
+    const RecordType *RT = CurrentType->getAs<RecordType>();
+    if (!RT) 
       return false;
-    if (LV.getLValueBase())
+    RecordDecl *RD = RT->getDecl();
+    const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
+    unsigned i = 0;
+    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;
-    return Success(LV.getLValueOffset().getQuantity(), E);
-  }
+    CurrentType = MemberDecl->getType().getNonReferenceType();
+  } 
+  return Success(Result.getQuantity(), E);
+}
 
+bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
+  // Special case unary operators that do not need their subexpression
+  // evaluated.  sizeof and alignof are special.
+  
   if (E->getOpcode() == UnaryOperator::LNot) {
     // LNot's operand isn't necessarily an integer, so we handle it specially.
     bool bres;
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp	(revisione 102050)
+++ lib/AST/StmtPrinter.cpp	(copia locale)
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/PrettyPrinter.h"
 #include "llvm/Support/Format.h"
+#include "clang/AST/Expr.h"
 using namespace clang;
 
 //===----------------------------------------------------------------------===//
@@ -76,8 +77,7 @@
       return OS;
     }
 
-    bool PrintOffsetOfDesignator(Expr *E);
-    void VisitUnaryOffsetOf(UnaryOperator *Node);
+    void PrintOffsetOfDesignator(OffsetOfExpr *E);
 
     void Visit(Stmt* S) {
       if (Helper && Helper->handledStmt(S,OS))
@@ -681,28 +681,29 @@
     OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
 }
 
-bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) {
-  if (isa<UnaryOperator>(E)) {
-    // Base case, print the type and comma.
-    OS << E->getType().getAsString() << ", ";
-    return true;
-  } else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
-    PrintOffsetOfDesignator(ASE->getLHS());
-    OS << "[";
-    PrintExpr(ASE->getRHS());
-    OS << "]";
-    return false;
-  } else {
-    MemberExpr *ME = cast<MemberExpr>(E);
-    bool IsFirst = PrintOffsetOfDesignator(ME->getBase());
-    OS << (IsFirst ? "" : ".") << ME->getMemberDecl();
-    return false;
+void StmtPrinter::PrintOffsetOfDesignator(OffsetOfExpr *E) {
+  OS << E->getTypeSourceInfo()->getType().getAsString() << ", ";
+  size_t n = E->getNumComponents();
+  assert(n > 0 && "Empty Vector of Components");
+  OS << E->getComponent(0).U.MemberDecl->getIdentifier()->getName();
+  for (unsigned i = 1; i < n; ++i) {
+    OffsetOfExpr::OffsetOfNode ON = E->getComponent(i);
+    if (ON.isBrackets) {
+      OS << "[";
+      PrintExpr(E->getIndexExpr(ON.U.ExprIndex));
+      OS << "]";
+    }
+    else { // FIXME: Are anonymous struct/union handled correctly?
+      IdentifierInfo *Info = ON.U.MemberDecl->getIdentifier();
+      if (Info)
+        OS << "." << Info->getName();
+    }
   }
 }
 
-void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) {
+void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
   OS << "__builtin_offsetof(";
-  PrintOffsetOfDesignator(Node->getSubExpr());
+  PrintOffsetOfDesignator(Node);
   OS << ")";
 }
 
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp	(revisione 102050)
+++ lib/AST/StmtProfile.cpp	(copia locale)
@@ -261,6 +261,17 @@
   ID.AddInteger(S->getOpcode());
 }
 
+void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) {
+  VisitType(S->getTypeSourceInfo()->getType());
+  unsigned n = S->getNumComponents();
+  for (unsigned i = 0; i < n; ++i) {
+    const OffsetOfExpr::OffsetOfNode& ON = S->getComponent(i);
+    if (!ON.isBrackets)
+      VisitDecl(ON.U.MemberDecl);
+  }
+  VisitExpr(S);
+}
+
 void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) {
   VisitExpr(S);
   ID.AddBoolean(S->isSizeOf());
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp	(revisione 102050)
+++ lib/AST/Expr.cpp	(copia locale)
@@ -391,7 +391,6 @@
   case Real:    return "__real";
   case Imag:    return "__imag";
   case Extension: return "__extension__";
-  case OffsetOf: return "__builtin_offsetof";
   }
 }
 
@@ -549,6 +548,45 @@
   return FnType->getResultType();
 }
 
+OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type, 
+                                   SourceLocation locStart, TypeSourceInfo *tsi, 
+                                   OffsetOfNode* compsPtr, unsigned numComps, 
+                                          Expr** exprsPtr, unsigned numExprs) {
+  void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
+                         sizeof(OffsetOfNode) * (numComps + 1) + 
+                         sizeof(Expr*) * (numExprs + 1));
+
+  return new (Mem) OffsetOfExpr(C, type, locStart, tsi, 
+                                compsPtr, numComps, exprsPtr, numExprs);
+}
+
+OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
+                                        unsigned numComps, unsigned numExprs) {
+  void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
+                         sizeof(OffsetOfNode) * (numComps + 1) + 
+                         sizeof(Expr*) * (numExprs + 1));
+  return new (Mem) OffsetOfExpr(numComps, numExprs);
+}
+
+OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, 
+                           SourceLocation locStart, TypeSourceInfo *tsi,
+                           OffsetOfNode* compsPtr, unsigned numComps, 
+                                  Expr** exprsPtr, unsigned numExprs)
+  : Expr(OffsetOfExprClass, type, false, false), LocStart(locStart), TSInfo(tsi), 
+    NumComps(numComps), NumExprs(numExprs) {
+
+  for(unsigned i = 0; i < numComps; ++i) {
+    setComponent(i, compsPtr[i]);
+  }
+  
+  LocEnd = compsPtr[numComps - 1].LocEnd;  
+
+  for(unsigned i = 0; i < numExprs; ++i) {
+    setIndexExpr(i, exprsPtr[i]);
+  }
+
+}
+
 MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
                                NestedNameSpecifier *qual,
                                SourceRange qualrange,
@@ -1893,7 +1931,9 @@
     case UnaryOperator::Real:
     case UnaryOperator::Imag:
       return CheckICE(Exp->getSubExpr(), Ctx);
-    case UnaryOperator::OffsetOf:
+    }
+  }
+  case Expr::OffsetOfExprClass: {
       // Note that per C99, offsetof must be an ICE. And AFAIK, using
       // Evaluate matches the proposed gcc behavior for cases like
       // "offsetof(struct s{int x[4];}, x[!.0])".  This doesn't affect
@@ -1901,7 +1941,6 @@
       // array subscripts that aren't ICEs, and if the array subscripts
       // are ICEs, the value of the offsetof must be an integer constant.
       return CheckEvalInICE(E, Ctx);
-    }
   }
   case Expr::SizeOfAlignOfExprClass: {
     const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E);
@@ -2694,6 +2733,16 @@
 Stmt::child_iterator UnaryOperator::child_begin() { return &Val; }
 Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; }
 
+// OffsetOfExpr
+Stmt::child_iterator OffsetOfExpr::child_begin() {
+  char* Ptr = static_cast<char*>(static_cast<void *>(this));
+  Ptr += sizeof(OffsetOfExpr) + sizeof(OffsetOfNode) * (NumComps + 1); 
+  return reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
+}
+Stmt::child_iterator OffsetOfExpr::child_end() {
+  return child_iterator(&*child_begin() + NumExprs);
+}
+
 // SizeOfAlignOfExpr
 Stmt::child_iterator SizeOfAlignOfExpr::child_begin() {
   // If this is of a type and the type is a VLA type (and not a typedef), the
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp	(revisione 102050)
+++ lib/CodeGen/CGExprScalar.cpp	(copia locale)
@@ -133,6 +133,7 @@
                                   CGF.getContext().typesAreCompatible(
                                     E->getArgType1(), E->getArgType2()));
   }
+  Value *VisitOffsetOfExpr(const OffsetOfExpr *E);
   Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
   Value *VisitAddrLabelExpr(const AddrLabelExpr *E) {
     llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel());
@@ -241,7 +242,6 @@
   Value *VisitUnaryExtension(const UnaryOperator *E) {
     return Visit(E->getSubExpr());
   }
-  Value *VisitUnaryOffsetOf(const UnaryOperator *E);
 
   // C++
   Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
@@ -1035,6 +1035,14 @@
   return Builder.CreateZExt(BoolVal, ConvertType(E->getType()), "lnot.ext");
 }
 
+Value *ScalarExprEmitter::VisitOffsetOfExpr(const OffsetOfExpr *E) {
+  Expr::EvalResult Result;
+  if(E->Evaluate(Result, CGF.getContext()))
+    return llvm::ConstantInt::get(VMContext, Result.Val.getInt());
+  else
+    return llvm::Constant::getNullValue(ConvertType(E->getType()));
+}
+
 /// VisitSizeOfAlignOfExpr - Return the size or alignment of the type of
 /// argument of the sizeof expression as an integer.
 Value *
@@ -1083,12 +1091,6 @@
   return llvm::Constant::getNullValue(ConvertType(E->getType()));
 }
 
-Value *ScalarExprEmitter::VisitUnaryOffsetOf(const UnaryOperator *E) {
-  Value* ResultAsPtr = EmitLValue(E->getSubExpr()).getAddress();
-  const llvm::Type* ResultType = ConvertType(E->getType());
-  return Builder.CreatePtrToInt(ResultAsPtr, ResultType, "offsetof");
-}
-
 //===----------------------------------------------------------------------===//
 //                           Binary Operators
 //===----------------------------------------------------------------------===//
Index: lib/Checker/GRExprEngine.cpp
===================================================================
--- lib/Checker/GRExprEngine.cpp	(revisione 102050)
+++ lib/Checker/GRExprEngine.cpp	(copia locale)
@@ -823,6 +823,10 @@
       VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
       break;
 
+    case Stmt::OffsetOfExprClass:
+      VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst);
+      break;
+
     case Stmt::SizeOfAlignOfExprClass:
       VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), Pred, Dst);
       break;
@@ -2613,6 +2617,21 @@
               ValMgr.makeIntVal(amt.getQuantity(), Ex->getType())));
 }
 
+void GRExprEngine::VisitOffsetOfExpr(OffsetOfExpr* OOE, ExplodedNode* Pred,
+                                     ExplodedNodeSet& Dst) {
+  Expr::EvalResult Res;
+  if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) {
+    const APSInt &IV = Res.Val.getInt();
+    assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
+    assert(OOE->getType()->isIntegerType());
+    assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
+    SVal X = ValMgr.makeIntVal(IV);
+    MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X));
+    return;
+  }
+  // FIXME: Handle the case where __builtin_offsetof is not a constant.
+  Dst.Add(Pred);
+}
 
 void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
                                       ExplodedNodeSet& Dst, bool asLValue) {
@@ -2691,22 +2710,6 @@
       return;
     }
 
-    case UnaryOperator::OffsetOf: {
-      Expr::EvalResult Res;
-      if (U->Evaluate(Res, getContext()) && Res.Val.isInt()) {
-        const APSInt &IV = Res.Val.getInt();
-        assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
-        assert(U->getType()->isIntegerType());
-        assert(IV.isSigned() == U->getType()->isSignedIntegerType());
-        SVal X = ValMgr.makeIntVal(IV);
-        MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
-        return;
-      }
-      // FIXME: Handle the case where __builtin_offsetof is not a constant.
-      Dst.Add(Pred);
-      return;
-    }
-
     case UnaryOperator::Plus: assert (!asLValue);  // FALL-THROUGH.
     case UnaryOperator::Extension: {
 
