[cfe-commits] r102542 - in /cfe/trunk: include/clang/AST/ include/clang/Checker/PathSensitive/ include/clang/Frontend/ lib/AST/ lib/Checker/ lib/CodeGen/ lib/Frontend/ lib/Sema/ test/PCH/ test/SemaCXX/ test/SemaTemplate/ tools/CIndex/

Douglas Gregor dgregor at apple.com
Wed Apr 28 15:16:22 PDT 2010


Author: dgregor
Date: Wed Apr 28 17:16:22 2010
New Revision: 102542

URL: http://llvm.org/viewvc/llvm-project?rev=102542&view=rev
Log:
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. 


Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/include/clang/AST/StmtNodes.def
    cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h
    cfe/trunk/include/clang/Frontend/PCHBitCodes.h
    cfe/trunk/include/clang/Frontend/StmtXML.def
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtProfile.cpp
    cfe/trunk/lib/Checker/GRExprEngine.cpp
    cfe/trunk/lib/CodeGen/CGExprScalar.cpp
    cfe/trunk/lib/Frontend/PCHReaderStmt.cpp
    cfe/trunk/lib/Frontend/PCHWriterStmt.cpp
    cfe/trunk/lib/Frontend/StmtXML.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaChecking.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/PCH/exprs.c
    cfe/trunk/test/PCH/exprs.h
    cfe/trunk/test/SemaCXX/offsetof.cpp
    cfe/trunk/test/SemaTemplate/instantiate-expr-5.cpp
    cfe/trunk/tools/CIndex/CIndex.cpp
    cfe/trunk/tools/CIndex/CXCursor.cpp

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Wed Apr 28 17:16:22 2010
@@ -223,7 +223,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 {
@@ -914,7 +914,7 @@
 ///
 /// __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.
+///   ArraySubscriptExpr's applied to it. (This is only used in C)
 ///
 class UnaryOperator : public Expr {
 public:
@@ -1003,6 +1003,187 @@
   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])*)
+  class OffsetOfNode {
+  public:
+    /// \brief The kind of offsetof node we have.
+    enum Kind {
+      Array = 0x00,
+      Field = 0x01,
+      Identifier = 0x02
+    };
+
+  private:
+    enum { MaskBits = 2, Mask = 0x03 };
+    
+    /// \brief The source range that covers this part of the designator.
+    SourceRange Range;
+    
+    /// \brief The data describing the designator, which comes in three
+    /// different forms, depending on the lower two bits.
+    ///   - An unsigned index into the array of Expr*'s stored after this node 
+    ///     in memory, for [constant-expression] designators.
+    ///   - A FieldDecl*, for references to a known field.
+    ///   - An IdentifierInfo*, for references to a field with a given name
+    ///     when the class type is dependent.
+    uintptr_t Data;
+    
+  public:
+    /// \brief Create an offsetof node that refers to an array element.
+    OffsetOfNode(SourceLocation LBracketLoc, unsigned Index, 
+                 SourceLocation RBracketLoc)
+      : Range(LBracketLoc, RBracketLoc), Data((Index << 2) | Array) { }
+    
+    /// \brief Create an offsetof node that refers to a field.
+    OffsetOfNode(SourceLocation DotLoc, FieldDecl *Field, 
+                 SourceLocation NameLoc)
+      : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc), 
+        Data(reinterpret_cast<uintptr_t>(Field) | OffsetOfNode::Field) { }
+    
+    /// \brief Create an offsetof node that refers to an identifier.
+    OffsetOfNode(SourceLocation DotLoc, IdentifierInfo *Name,
+                 SourceLocation NameLoc)
+      : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc), 
+        Data(reinterpret_cast<uintptr_t>(Name) | Identifier) { }
+    
+    /// \brief Determine what kind of offsetof node this is.
+    Kind getKind() const { 
+      return static_cast<Kind>(Data & Mask);
+    }
+    
+    /// \brief For an array element node, returns the index into the array
+    /// of expressions.
+    unsigned getArrayExprIndex() const {
+      assert(getKind() == Array);
+      return Data >> 2;
+    }
+
+    /// \brief For a field offsetof node, returns the field.
+    FieldDecl *getField() const {
+      assert(getKind() == Field);
+      return reinterpret_cast<FieldDecl *> (Data & ~(uintptr_t)Mask);
+    }
+    
+    /// \brief For a field or identifier offsetof node, returns the name of
+    /// the field.
+    IdentifierInfo *getFieldName() const;
+    
+    /// \brief Retrieve the source range that covers this offsetof node.
+    ///
+    /// For an array element node, the source range contains the locations of
+    /// the square brackets. For a field or identifier node, the source range
+    /// contains the location of the period (if there is one) and the 
+    /// identifier.
+    SourceRange getRange() const { return Range; }
+  };
+
+private:
+  
+  SourceLocation OperatorLoc, RParenLoc;
+  // 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 OperatorLoc, TypeSourceInfo *tsi,
+               OffsetOfNode* compsPtr, unsigned numComps, 
+               Expr** exprsPtr, unsigned numExprs,
+               SourceLocation RParenLoc);
+
+  explicit OffsetOfExpr(unsigned numComps, unsigned numExprs)
+    : Expr(OffsetOfExprClass, EmptyShell()),
+      TSInfo(0), NumComps(numComps), NumExprs(numExprs) {}  
+
+public:
+  
+  static OffsetOfExpr *Create(ASTContext &C, QualType type, 
+                              SourceLocation OperatorLoc, TypeSourceInfo *tsi, 
+                              OffsetOfNode* compsPtr, unsigned numComps, 
+                              Expr** exprsPtr, unsigned numExprs,
+                              SourceLocation RParenLoc);
+
+  static OffsetOfExpr *CreateEmpty(ASTContext &C, 
+                                   unsigned NumComps, unsigned NumExprs);
+
+  /// getOperatorLoc - Return the location of the operator.
+  SourceLocation getOperatorLoc() const { return OperatorLoc; }
+  void setOperatorLoc(SourceLocation L) { OperatorLoc = L; }
+
+  /// \brief Return the location of the right parentheses.
+  SourceLocation getRParenLoc() const { return RParenLoc; }
+  void setRParenLoc(SourceLocation R) { RParenLoc = R; }
+  
+  TypeSourceInfo *getTypeSourceInfo() const {
+    return TSInfo;
+  }
+  void setTypeSourceInfo(TypeSourceInfo *tsi) {
+    TSInfo = tsi;
+  }
+  
+  const OffsetOfNode &getComponent(unsigned Idx) {
+    assert(Idx < NumComps && "Subscript out of range");
+    return reinterpret_cast<OffsetOfNode *> (this + 1)[Idx];
+  }
+
+  void setComponent(unsigned Idx, OffsetOfNode ON) {
+    assert(Idx < NumComps && "Subscript out of range");
+    reinterpret_cast<OffsetOfNode *> (this + 1)[Idx] = ON;
+  }
+  
+  unsigned getNumComponents() const {
+    return NumComps;
+  }
+
+  Expr* getIndexExpr(unsigned Idx) {
+    assert(Idx < NumExprs && "Subscript out of range");
+    return reinterpret_cast<Expr **>(
+                    reinterpret_cast<OffsetOfNode *>(this+1) + NumComps)[Idx];
+  }
+
+  void setIndexExpr(unsigned Idx, Expr* E) {
+    assert(Idx < NumComps && "Subscript out of range");
+    reinterpret_cast<Expr **>(
+                reinterpret_cast<OffsetOfNode *>(this+1) + NumComps)[Idx] = E;
+  }
+  
+  unsigned getNumExpressions() const {
+    return NumExprs;
+  }
+
+  virtual SourceRange getSourceRange() const {
+    return SourceRange(OperatorLoc, RParenLoc);
+  }
+
+  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 {

Modified: cfe/trunk/include/clang/AST/StmtNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtNodes.def?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtNodes.def (original)
+++ cfe/trunk/include/clang/AST/StmtNodes.def Wed Apr 28 17:16:22 2010
@@ -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)

Modified: cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Checker/PathSensitive/GRExprEngine.h Wed Apr 28 17:16:22 2010
@@ -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,

Modified: cfe/trunk/include/clang/Frontend/PCHBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PCHBitCodes.h?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/PCHBitCodes.h (original)
+++ cfe/trunk/include/clang/Frontend/PCHBitCodes.h Wed Apr 28 17:16:22 2010
@@ -603,6 +603,8 @@
       EXPR_PAREN,
       /// \brief A UnaryOperator record.
       EXPR_UNARY_OPERATOR,
+      /// \brief An OffsetOfExpr record.
+      EXPR_OFFSETOF,
       /// \brief A SizefAlignOfExpr record.
       EXPR_SIZEOF_ALIGN_OF,
       /// \brief An ArraySubscriptExpr record.

Modified: cfe/trunk/include/clang/Frontend/StmtXML.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/StmtXML.def?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/StmtXML.def (original)
+++ cfe/trunk/include/clang/Frontend/StmtXML.def Wed Apr 28 17:16:22 2010
@@ -254,7 +254,7 @@
     ENUM_XML(UnaryOperator::Real,    "__real")
     ENUM_XML(UnaryOperator::Imag,    "__imag")
     ENUM_XML(UnaryOperator::Extension, "__extension__")
-    ENUM_XML(UnaryOperator::OffsetOf,  "__builtin_offsetof")
+    ENUM_XML(UnaryOperator::OffsetOf, "__builtin_offsetof")
   END_ENUM_XML
   SUB_NODE_XML(Expr)                                    // expr
 END_NODE_XML
@@ -311,6 +311,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())

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Wed Apr 28 17:16:22 2010
@@ -549,6 +549,57 @@
   return FnType->getResultType();
 }
 
+OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type, 
+                                   SourceLocation OperatorLoc,
+                                   TypeSourceInfo *tsi, 
+                                   OffsetOfNode* compsPtr, unsigned numComps, 
+                                   Expr** exprsPtr, unsigned numExprs,
+                                   SourceLocation RParenLoc) {
+  void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
+                         sizeof(OffsetOfNode) * numComps + 
+                         sizeof(Expr*) * numExprs);
+
+  return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, compsPtr, numComps,
+                                exprsPtr, numExprs, RParenLoc);
+}
+
+OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
+                                        unsigned numComps, unsigned numExprs) {
+  void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
+                         sizeof(OffsetOfNode) * numComps +
+                         sizeof(Expr*) * numExprs);
+  return new (Mem) OffsetOfExpr(numComps, numExprs);
+}
+
+OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, 
+                           SourceLocation OperatorLoc, TypeSourceInfo *tsi,
+                           OffsetOfNode* compsPtr, unsigned numComps, 
+                           Expr** exprsPtr, unsigned numExprs,
+                           SourceLocation RParenLoc)
+  : Expr(OffsetOfExprClass, type, /*TypeDependent=*/false, 
+         /*ValueDependent=*/tsi->getType()->isDependentType() ||
+         hasAnyTypeDependentArguments(exprsPtr, numExprs) ||
+         hasAnyValueDependentArguments(exprsPtr, numExprs)),
+    OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi), 
+    NumComps(numComps), NumExprs(numExprs) 
+{
+  for(unsigned i = 0; i < numComps; ++i) {
+    setComponent(i, compsPtr[i]);
+  }
+  
+  for(unsigned i = 0; i < numExprs; ++i) {
+    setIndexExpr(i, exprsPtr[i]);
+  }
+}
+
+IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const {
+  assert(getKind() == Field || getKind() == Identifier);
+  if (getKind() == Field)
+    return getField()->getIdentifier();
+  
+  return reinterpret_cast<IdentifierInfo *> (Data & ~(uintptr_t)Mask);
+}
+
 MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
                                NestedNameSpecifier *qual,
                                SourceRange qualrange,
@@ -1891,7 +1942,7 @@
     case UnaryOperator::AddrOf:
     case UnaryOperator::Deref:
       return ICEDiag(2, E->getLocStart());
-
+    case UnaryOperator::OffsetOf:
     case UnaryOperator::Extension:
     case UnaryOperator::LNot:
     case UnaryOperator::Plus:
@@ -1900,7 +1951,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
@@ -1908,7 +1961,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);
@@ -2702,6 +2754,15 @@
 Stmt::child_iterator UnaryOperator::child_begin() { return &Val; }
 Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; }
 
+// OffsetOfExpr
+Stmt::child_iterator OffsetOfExpr::child_begin() {
+  return reinterpret_cast<Stmt **> (reinterpret_cast<OffsetOfNode *> (this + 1)
+                                      + NumComps);
+}
+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

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Wed Apr 28 17:16:22 2010
@@ -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;

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Wed Apr 28 17:16:22 2010
@@ -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;
 
 //===----------------------------------------------------------------------===//
@@ -703,6 +704,35 @@
   OS << ")";
 }
 
+void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
+  OS << "__builtin_offsetof(";
+  OS << Node->getTypeSourceInfo()->getType().getAsString() << ", ";
+  bool PrintedSomething = false;
+  for (unsigned i = 0, n = Node->getNumComponents(); i < n; ++i) {
+    OffsetOfExpr::OffsetOfNode ON = Node->getComponent(i);
+    if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Array) {
+      // Array node
+      OS << "[";
+      PrintExpr(Node->getIndexExpr(ON.getArrayExprIndex()));
+      OS << "]";
+      PrintedSomething = true;
+      continue;
+    }
+     
+    // Field or identifier node.
+    IdentifierInfo *Id = ON.getFieldName();
+    if (!Id)
+      continue;
+    
+    if (PrintedSomething)
+      OS << ".";
+    else
+      PrintedSomething = true;
+    OS << Id->getName();    
+  }
+  OS << ")";
+}
+
 void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
   OS << (Node->isSizeOf() ? "sizeof" : "__alignof");
   if (Node->isArgumentType())

Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Wed Apr 28 17:16:22 2010
@@ -261,6 +261,30 @@
   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);
+    ID.AddInteger(ON.getKind());
+    switch (ON.getKind()) {
+    case OffsetOfExpr::OffsetOfNode::Array:
+      // Expressions handled below.
+      break;
+
+    case OffsetOfExpr::OffsetOfNode::Field:
+      VisitDecl(ON.getField());
+      break;
+
+    case OffsetOfExpr::OffsetOfNode::Identifier:
+      ID.AddPointer(ON.getFieldName());
+      break;
+    }
+  }
+  
+  VisitExpr(S);
+}
+
 void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) {
   VisitExpr(S);
   ID.AddBoolean(S->isSizeOf());

Modified: cfe/trunk/lib/Checker/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/GRExprEngine.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Checker/GRExprEngine.cpp Wed Apr 28 17:16:22 2010
@@ -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;
@@ -2611,6 +2615,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) {
@@ -2692,19 +2711,19 @@
     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;
-      }
+          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: {
 

Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Wed Apr 28 17:16:22 2010
@@ -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());
@@ -242,7 +243,7 @@
     return Visit(E->getSubExpr());
   }
   Value *VisitUnaryOffsetOf(const UnaryOperator *E);
-
+    
   // C++
   Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
     return Visit(DAE->getExpr());
@@ -1030,6 +1031,21 @@
   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());
+  
+  // FIXME: Cannot support code generation for non-constant offsetof.
+  unsigned DiagID = CGF.CGM.getDiags().getCustomDiagID(Diagnostic::Error,
+                             "cannot compile non-constant __builtin_offsetof");
+  CGF.CGM.getDiags().Report(CGF.getContext().getFullLoc(E->getLocStart()), 
+                            DiagID)
+    << E->getSourceRange();
+  
+  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 *

Modified: cfe/trunk/lib/Frontend/PCHReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHReaderStmt.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHReaderStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHReaderStmt.cpp Wed Apr 28 17:16:22 2010
@@ -71,6 +71,7 @@
     unsigned VisitCharacterLiteral(CharacterLiteral *E);
     unsigned VisitParenExpr(ParenExpr *E);
     unsigned VisitUnaryOperator(UnaryOperator *E);
+    unsigned VisitOffsetOfExpr(OffsetOfExpr *E);
     unsigned VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
     unsigned VisitArraySubscriptExpr(ArraySubscriptExpr *E);
     unsigned VisitCallExpr(CallExpr *E);
@@ -432,6 +433,44 @@
   return 1;
 }
 
+unsigned PCHStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) {
+  typedef OffsetOfExpr::OffsetOfNode Node;
+  VisitExpr(E);
+  assert(E->getNumComponents() == Record[Idx]);
+  ++Idx;
+  assert(E->getNumExpressions() == Record[Idx]);
+  ++Idx;
+  E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+  E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+  E->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
+  for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
+    Node::Kind Kind = static_cast<Node::Kind>(Record[Idx++]);
+    SourceLocation Start = SourceLocation::getFromRawEncoding(Record[Idx++]);
+    SourceLocation End = SourceLocation::getFromRawEncoding(Record[Idx++]);
+    switch (Kind) {
+    case Node::Array:
+      E->setComponent(I, Node(Start, Record[Idx++], End));
+      break;
+        
+    case Node::Field:
+      E->setComponent(I, 
+             Node(Start,  
+                  dyn_cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])),
+                  End));
+      break;
+
+    case Node::Identifier:
+      E->setComponent(I, Node(Start, Reader.GetIdentifier(Record[Idx++]), End));
+      break;
+    }
+  }
+  
+  for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I)
+    E->setIndexExpr(I, cast_or_null<Expr>(StmtStack[StmtStack.size() - N + I]));
+  
+  return E->getNumExpressions();
+}
+
 unsigned PCHStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
   VisitExpr(E);
   E->setSizeof(Record[Idx++]);
@@ -1105,6 +1144,12 @@
       S = new (Context) UnaryOperator(Empty);
       break;
 
+    case pch::EXPR_OFFSETOF:
+      S = OffsetOfExpr::CreateEmpty(*Context, 
+                                    Record[PCHStmtReader::NumExprFields],
+                                    Record[PCHStmtReader::NumExprFields + 1]);
+      break;
+        
     case pch::EXPR_SIZEOF_ALIGN_OF:
       S = new (Context) SizeOfAlignOfExpr(Empty);
       break;

Modified: cfe/trunk/lib/Frontend/PCHWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/PCHWriterStmt.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/PCHWriterStmt.cpp (original)
+++ cfe/trunk/lib/Frontend/PCHWriterStmt.cpp Wed Apr 28 17:16:22 2010
@@ -62,6 +62,7 @@
     void VisitCharacterLiteral(CharacterLiteral *E);
     void VisitParenExpr(ParenExpr *E);
     void VisitUnaryOperator(UnaryOperator *E);
+    void VisitOffsetOfExpr(OffsetOfExpr *E);
     void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
     void VisitArraySubscriptExpr(ArraySubscriptExpr *E);
     void VisitCallExpr(CallExpr *E);
@@ -393,6 +394,37 @@
   Code = pch::EXPR_UNARY_OPERATOR;
 }
 
+void PCHStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) {
+  VisitExpr(E);
+  Record.push_back(E->getNumComponents());
+  Record.push_back(E->getNumExpressions());
+  Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+  Writer.AddSourceLocation(E->getRParenLoc(), Record);
+  Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
+  for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
+    const OffsetOfExpr::OffsetOfNode &ON = E->getComponent(I);
+    Record.push_back(ON.getKind()); // FIXME: Stable encoding
+    Writer.AddSourceLocation(ON.getRange().getBegin(), Record);
+    Writer.AddSourceLocation(ON.getRange().getEnd(), Record);
+    switch (ON.getKind()) {
+    case OffsetOfExpr::OffsetOfNode::Array:
+      Record.push_back(ON.getArrayExprIndex());
+      break;
+        
+    case OffsetOfExpr::OffsetOfNode::Field:
+      Writer.AddDeclRef(ON.getField(), Record);
+      break;
+        
+    case OffsetOfExpr::OffsetOfNode::Identifier:
+      Writer.AddIdentifierRef(ON.getFieldName(), Record);
+      break;
+    }
+  }
+  for (unsigned I = 0, N = E->getNumExpressions(); I != N; ++I)
+    Writer.WriteSubStmt(E->getIndexExpr(I));
+  Code = pch::EXPR_OFFSETOF;
+}
+
 void PCHStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
   VisitExpr(E);
   Record.push_back(E->isSizeOf());

Modified: cfe/trunk/lib/Frontend/StmtXML.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/StmtXML.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/StmtXML.cpp (original)
+++ cfe/trunk/lib/Frontend/StmtXML.cpp Wed Apr 28 17:16:22 2010
@@ -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);
@@ -308,6 +309,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");

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Apr 28 17:16:22 2010
@@ -1986,6 +1986,11 @@
                                          SourceLocation RPLoc); // "({..})"
 
   /// __builtin_offsetof(type, a.b[123][456].c)
+  OwningExprResult BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
+                                        TypeSourceInfo *TInfo,
+                                        OffsetOfComponent *CompPtr,
+                                        unsigned NumComponents,
+                                        SourceLocation RParenLoc);
   virtual OwningExprResult ActOnBuiltinOffsetOf(Scope *S,
                                                 SourceLocation BuiltinLoc,
                                                 SourceLocation TypeLoc,

Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Wed Apr 28 17:16:22 2010
@@ -1950,6 +1950,10 @@
       return GetExprRange(C, UO->getSubExpr(), MaxWidth);
     }
   }
+  
+  if (dyn_cast<OffsetOfExpr>(E)) {
+    IntRange::forType(C, E->getType());
+  }
 
   FieldDecl *BitField = E->getBitField();
   if (BitField) {

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Apr 28 17:16:22 2010
@@ -18,8 +18,10 @@
 #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/AST/TypeLoc.h"
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
@@ -6450,7 +6452,7 @@
   case UnaryOperator::OffsetOf:
     assert(false && "Invalid unary operator");
     break;
-
+      
   case UnaryOperator::PreInc:
   case UnaryOperator::PreDec:
   case UnaryOperator::PostInc:
@@ -6608,6 +6610,134 @@
   return Owned(new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc));
 }
 
+Sema::OwningExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc,
+                                                  TypeSourceInfo *TInfo,
+                                                  OffsetOfComponent *CompPtr,
+                                                  unsigned NumComponents,
+                                                  SourceLocation RParenLoc) {
+  QualType ArgTy = TInfo->getType();
+  bool Dependent = ArgTy->isDependentType();
+  SourceRange TypeRange = TInfo->getTypeLoc().getSourceRange();
+  
+  // We must have at least one component that refers to the type, and the first
+  // one is known to be a field designator.  Verify that the ArgTy represents
+  // a struct/union/class.
+  if (!Dependent && !ArgTy->isRecordType())
+    return ExprError(Diag(BuiltinLoc, diag::err_offsetof_record_type) 
+                       << ArgTy << TypeRange);
+  
+  // Type must be complete per C99 7.17p3 because a declaring a variable
+  // with an incomplete type would be ill-formed.
+  if (!Dependent 
+      && RequireCompleteType(BuiltinLoc, ArgTy,
+                             PDiag(diag::err_offsetof_incomplete_type)
+                               << TypeRange))
+    return ExprError();
+  
+  // 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
+  // a system header!
+  if (NumComponents != 1)
+    Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator)
+      << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd);
+  
+  bool DidWarnAboutNonPOD = false;
+  QualType CurrentType = ArgTy;
+  typedef OffsetOfExpr::OffsetOfNode OffsetOfNode;
+  llvm::SmallVector<OffsetOfNode, 4> Comps;
+  llvm::SmallVector<Expr*, 4> Exprs;
+  for (unsigned i = 0; i != NumComponents; ++i) {
+    const OffsetOfComponent &OC = CompPtr[i];
+    if (OC.isBrackets) {
+      // Offset of an array sub-field.  TODO: Should we allow vector elements?
+      if (!CurrentType->isDependentType()) {
+        const ArrayType *AT = Context.getAsArrayType(CurrentType);
+        if(!AT)
+          return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type)
+                           << CurrentType);
+        CurrentType = AT->getElementType();
+      } else
+        CurrentType = Context.DependentTy;
+      
+      // The expression must be an integral expression.
+      // FIXME: An integral constant expression?
+      Expr *Idx = static_cast<Expr*>(OC.U.E);
+      if (!Idx->isTypeDependent() && !Idx->isValueDependent() &&
+          !Idx->getType()->isIntegerType())
+        return ExprError(Diag(Idx->getLocStart(),
+                              diag::err_typecheck_subscript_not_integer)
+                         << Idx->getSourceRange());
+      
+      // Record this array index.
+      Comps.push_back(OffsetOfNode(OC.LocStart, Exprs.size(), OC.LocEnd));
+      Exprs.push_back(Idx);
+      continue;
+    }
+    
+    // Offset of a field.
+    if (CurrentType->isDependentType()) {
+      // We have the offset of a field, but we can't look into the dependent
+      // type. Just record the identifier of the field.
+      Comps.push_back(OffsetOfNode(OC.LocStart, OC.U.IdentInfo, OC.LocEnd));
+      CurrentType = Context.DependentTy;
+      continue;
+    }
+    
+    // We need to have a complete type to look into.
+    if (RequireCompleteType(OC.LocStart, CurrentType,
+                            diag::err_offsetof_incomplete_type))
+      return ExprError();
+    
+    // Look for the designated field.
+    const RecordType *RC = CurrentType->getAs<RecordType>();
+    if (!RC) 
+      return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
+                       << CurrentType);
+    RecordDecl *RD = RC->getDecl();
+    
+    // C++ [lib.support.types]p5:
+    //   The macro offsetof accepts a restricted set of type arguments in this
+    //   International Standard. type shall be a POD structure or a POD union
+    //   (clause 9).
+    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)
+                              << CurrentType))
+        DidWarnAboutNonPOD = true;
+    }
+    
+    // Look for the field.
+    LookupResult R(*this, OC.U.IdentInfo, OC.LocStart, LookupMemberName);
+    LookupQualifiedName(R, RD);
+    FieldDecl *MemberDecl = R.getAsSingle<FieldDecl>();
+    if (!MemberDecl)
+      return ExprError(Diag(BuiltinLoc, diag::err_no_member)
+                       << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, 
+                                                              OC.LocEnd));
+    
+    // FIXME: C99 Verify that MemberDecl isn't a bitfield.
+    
+    if (cast<RecordDecl>(MemberDecl->getDeclContext())->
+        isAnonymousStructOrUnion()) {
+      llvm::SmallVector<FieldDecl*, 4> Path;
+      BuildAnonymousStructUnionMemberPath(MemberDecl, Path);
+      unsigned n = Path.size();
+      for (int j = n - 1; j > -1; --j)
+        Comps.push_back(OffsetOfNode(OC.LocStart, Path[j], OC.LocEnd));
+    } else {
+      Comps.push_back(OffsetOfNode(OC.LocStart, MemberDecl, OC.LocEnd));
+    }
+    CurrentType = MemberDecl->getType().getNonReferenceType(); 
+  }
+  
+  return Owned(OffsetOfExpr::Create(Context, Context.getSizeType(), BuiltinLoc, 
+                                    TInfo, Comps.data(), Comps.size(),
+                                    Exprs.data(), Exprs.size(), RParenLoc));  
+}
+
 Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
                                                   SourceLocation BuiltinLoc,
                                                   SourceLocation TypeLoc,
@@ -6615,45 +6745,56 @@
                                                   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!");
 
-  bool Dependent = ArgTy->isDependentType();
+  TypeSourceInfo *ArgTInfo;
+  QualType ArgTy = GetTypeFromParser(argty, &ArgTInfo);
+  if (ArgTy.isNull())
+    return ExprError();
 
+  if (getLangOptions().CPlusPlus) {
+    if (!ArgTInfo)
+      ArgTInfo = Context.getTrivialTypeSourceInfo(ArgTy, TypeLoc);
+    
+    return BuildBuiltinOffsetOf(BuiltinLoc, ArgTInfo, CompPtr, NumComponents, 
+                                RPLoc);
+  }
+  
+  // FIXME: The code below is marked for death, once we have proper CodeGen
+  // support for non-constant OffsetOf expressions.
+  
+  bool Dependent = ArgTy->isDependentType();
+  
   // We must have at least one component that refers to the type, and the first
   // one is known to be a field designator.  Verify that the ArgTy represents
   // a struct/union/class.
   if (!Dependent && !ArgTy->isRecordType())
     return ExprError(Diag(TypeLoc, diag::err_offsetof_record_type) << ArgTy);
-
+  
   // FIXME: Type must be complete per C99 7.17p3 because a declaring a variable
   // with an incomplete type would be illegal.
-
+  
   // 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
   // a system header!
   if (NumComponents != 1)
     Diag(BuiltinLoc, diag::ext_offsetof_extended_field_designator)
-      << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd);
-
+    << SourceRange(CompPtr[1].LocStart, CompPtr[NumComponents-1].LocEnd);
+  
   if (!Dependent) {
     bool DidWarnAboutNonPOD = false;
-
+    
     if (RequireCompleteType(TypeLoc, Res->getType(),
                             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) {
@@ -6664,71 +6805,71 @@
         if (!AT) {
           Res->Destroy(Context);
           return ExprError(Diag(OC.LocEnd, diag::err_offsetof_array_type)
-            << Res->getType());
+                           << Res->getType());
         }
-
+        
         // 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());
-
+                           << Idx->getSourceRange());
+        
         Res = new (Context) ArraySubscriptExpr(Res, Idx, AT->getElementType(),
                                                OC.LocEnd);
         continue;
       }
-
+      
       const RecordType *RC = Res->getType()->getAs<RecordType>();
       if (!RC) {
         Res->Destroy(Context);
         return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type)
-          << Res->getType());
+                         << Res->getType());
       }
-
+      
       // Get the decl corresponding to this.
       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()))
+                                << SourceRange(CompPtr[0].LocStart, OC.LocEnd)
+                                << Res->getType()))
           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>();
+                                                       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());
+                                       MemberDecl->getType().getNonReferenceType());
       }
     }
   }
-
+  
   return Owned(new (Context) UnaryOperator(Res, UnaryOperator::OffsetOf,
                                            Context.getSizeType(), BuiltinLoc));
 }

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Wed Apr 28 17:16:22 2010
@@ -1067,6 +1067,19 @@
     return getSema().BuildUnaryOp(/*Scope=*/0, OpLoc, Opc, move(SubExpr));
   }
 
+  /// \brief Build a new builtin offsetof expression.
+  ///
+  /// By default, performs semantic analysis to build the new expression.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningExprResult RebuildOffsetOfExpr(SourceLocation OperatorLoc,
+                                       TypeSourceInfo *Type,
+                                       Action::OffsetOfComponent *Components,
+                                       unsigned NumComponents,
+                                       SourceLocation RParenLoc) {
+    return getSema().BuildBuiltinOffsetOf(OperatorLoc, Type, Components,
+                                          NumComponents, RParenLoc);
+  }
+  
   /// \brief Build a new sizeof or alignof expression with a type argument.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -4168,6 +4181,64 @@
 
 template<typename Derived>
 Sema::OwningExprResult
+TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) {
+  // Transform the type.
+  TypeSourceInfo *Type = getDerived().TransformType(E->getTypeSourceInfo());
+  if (!Type)
+    return getSema().ExprError();
+  
+  // Transform all of the components into components similar to what the
+  // parser uses.
+  // FIXME: It would be slightly more efficient in the non-dependent case to 
+  // just map FieldDecls, rather than requiring the rebuilder to look for 
+  // the fields again. However, __builtin_offsetof is rare enough in 
+  // template code that we don't care.
+  bool ExprChanged = false;
+  typedef Action::OffsetOfComponent Component;
+  typedef OffsetOfExpr::OffsetOfNode Node;
+  llvm::SmallVector<Component, 4> Components;
+  for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) {
+    const Node &ON = E->getComponent(I);
+    Component Comp;
+    Comp.LocStart = ON.getRange().getBegin();
+    Comp.LocEnd = ON.getRange().getEnd();
+    switch (ON.getKind()) {
+    case Node::Array: {
+      Expr *FromIndex = E->getIndexExpr(ON.getArrayExprIndex());
+      OwningExprResult Index = getDerived().TransformExpr(FromIndex);
+      if (Index.isInvalid())
+        return getSema().ExprError();
+      
+      ExprChanged = ExprChanged || Index.get() != FromIndex;
+      Comp.isBrackets = true;
+      Comp.U.E = Index.takeAs<Expr>(); // FIXME: leaked
+      break;
+    }
+        
+    case Node::Field:
+    case Node::Identifier:
+      Comp.isBrackets = false;
+      Comp.U.IdentInfo = ON.getFieldName();
+      break;
+    }
+    
+    Components.push_back(Comp);
+  }
+  
+  // If nothing changed, retain the existing expression.
+  if (!getDerived().AlwaysRebuild() &&
+      Type == E->getTypeSourceInfo() &&
+      !ExprChanged)
+    return SemaRef.Owned(E->Retain());
+  
+  // Build a new offsetof expression.
+  return getDerived().RebuildOffsetOfExpr(E->getOperatorLoc(), Type,
+                                          Components.data(), Components.size(),
+                                          E->getRParenLoc());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
 TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
   if (E->isArgumentType()) {
     TypeSourceInfo *OldT = E->getArgumentTypeInfo();

Modified: cfe/trunk/test/PCH/exprs.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/exprs.c?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/test/PCH/exprs.c (original)
+++ cfe/trunk/test/PCH/exprs.c Wed Apr 28 17:16:22 2010
@@ -5,6 +5,7 @@
 // RUN: %clang_cc1 -emit-pch -fblocks -o %t %S/exprs.h
 // RUN: %clang_cc1 -fblocks -include-pch %t -fsyntax-only -verify %s 
 
+__SIZE_TYPE__ size_type_value;
 int integer;
 long long_integer;
 double floating;
@@ -35,6 +36,9 @@
 // UnaryOperator
 negate_enum *int_ptr4 = &integer;
 
+// OffsetOfExpr
+offsetof_type *offsetof_ptr = &size_type_value;
+
 // SizeOfAlignOfExpr
 typeof(sizeof(float)) size_t_value;
 typeof_sizeof *size_t_ptr = &size_t_value;

Modified: cfe/trunk/test/PCH/exprs.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/exprs.h?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/test/PCH/exprs.h (original)
+++ cfe/trunk/test/PCH/exprs.h Wed Apr 28 17:16:22 2010
@@ -25,6 +25,19 @@
 // UnaryOperator
 typedef typeof(-Enumerator) negate_enum;
 
+// OffsetOfExpr
+struct X {
+  int member;
+};
+struct Y {
+  struct X array[5];
+};
+struct Z {
+  struct Y y;
+};
+typedef typeof(__builtin_offsetof(struct Z, y.array[1 + 2].member)) 
+  offsetof_type;
+
 // SizeOfAlignOfExpr
 typedef typeof(sizeof(int)) typeof_sizeof;
 typedef typeof(sizeof(Enumerator)) typeof_sizeof2;

Modified: cfe/trunk/test/SemaCXX/offsetof.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/offsetof.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/offsetof.cpp (original)
+++ cfe/trunk/test/SemaCXX/offsetof.cpp Wed Apr 28 17:16:22 2010
@@ -18,3 +18,13 @@
 int o = __builtin_offsetof(Derived, x); // expected-warning{{offset of on non-POD type}}
 
 const int o2 = sizeof(__builtin_offsetof(Derived, x));
+
+struct HasArray {
+  int array[17];
+};
+
+// Constant and non-constant offsetof expressions
+void test_ice(int i) {
+  int array0[__builtin_offsetof(HasArray, array[5])];
+  int array1[__builtin_offsetof(HasArray, array[i])]; // expected-error{{variable length arrays are not permitted in C++}}
+}

Modified: cfe/trunk/test/SemaTemplate/instantiate-expr-5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-expr-5.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-expr-5.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-expr-5.cpp Wed Apr 28 17:16:22 2010
@@ -1,4 +1,22 @@
-// RUN: %clang_cc1 -fsyntax-only %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s
 
 template <class A> int x(A x) { return x++; }
 int y() { return x<int>(1); }
+
+namespace PR5880 {
+  template<typename T>
+  struct A { 
+    static const int a  = __builtin_offsetof(T, a.array[5].m); // expected-error{{error: no member named 'a' in 'HasM'}}
+  };
+  struct HasM {
+    float m;
+  };
+
+  struct ArrayOfHasM {
+    HasM array[10];
+  };
+
+  struct B { ArrayOfHasM a; };
+  A<B> x;
+  A<HasM> x2; // expected-note{{in instantiation of}}
+}

Modified: cfe/trunk/tools/CIndex/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CIndex.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/tools/CIndex/CIndex.cpp (original)
+++ cfe/trunk/tools/CIndex/CIndex.cpp Wed Apr 28 17:16:22 2010
@@ -306,6 +306,7 @@
   bool VisitExplicitCastExpr(ExplicitCastExpr *E);
   bool VisitObjCMessageExpr(ObjCMessageExpr *E);
   bool VisitObjCEncodeExpr(ObjCEncodeExpr *E);
+  bool VisitOffsetOfExpr(OffsetOfExpr *E);
   bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
 };
 
@@ -943,6 +944,14 @@
   return Visit(B->getBlockDecl());
 }
 
+bool CursorVisitor::VisitOffsetOfExpr(OffsetOfExpr *E) {
+  // FIXME: Visit fields as well?
+  if (Visit(E->getTypeSourceInfo()->getTypeLoc()))
+    return true;
+  
+  return VisitExpr(E);
+}
+
 bool CursorVisitor::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
   if (E->isArgumentType()) {
     if (TypeSourceInfo *TSInfo = E->getArgumentTypeInfo())

Modified: cfe/trunk/tools/CIndex/CXCursor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/CIndex/CXCursor.cpp?rev=102542&r1=102541&r2=102542&view=diff
==============================================================================
--- cfe/trunk/tools/CIndex/CXCursor.cpp (original)
+++ cfe/trunk/tools/CIndex/CXCursor.cpp Wed Apr 28 17:16:22 2010
@@ -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:        





More information about the cfe-commits mailing list