aboutsummaryrefslogtreecommitdiff
path: root/include/clang
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-04-28 22:16:22 +0000
committerDouglas Gregor <dgregor@apple.com>2010-04-28 22:16:22 +0000
commit8ecdb65716cd7914ffb2eeee993fa9039fcd31e8 (patch)
treecba751b09dbf3a8fe4aa9114a7d7880095b9d199 /include/clang
parent109dfc6ca6652f60c55ed0f2631aebf323d0200d (diff)
Completely reimplement __builtin_offsetof, based on a patch by Roberto
Amadini. This change introduces a new expression node type, OffsetOfExpr, that describes __builtin_offsetof. Previously, __builtin_offsetof was implemented using a unary operator whose subexpression involved various synthesized array-subscript and member-reference expressions, which was ugly and made it very hard to instantiate as a template. OffsetOfExpr represents the AST more faithfully, with proper type source information and a more compact representation. OffsetOfExpr also has support for dependent __builtin_offsetof expressions; it can be value-dependent, but will never be type-dependent (like sizeof or alignof). This commit introduces template instantiation for __builtin_offsetof as well. There are two major caveats to this patch: 1) CodeGen cannot handle the case where __builtin_offsetof is not a constant expression, so it produces an error. So, to avoid regressing in C, we retain the old UnaryOperator-based __builtin_offsetof implementation in C while using the shiny new OffsetOfExpr implementation in C++. The old implementation can go away once we have proper CodeGen support for this case, which we expect won't cause much trouble in C++. 2) __builtin_offsetof doesn't work well with non-POD class types, particularly when the designated field is found within a base class. I will address this in a subsequent patch. Fixes PR5880 and a bunch of assertions when building Boost.Python tests. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102542 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include/clang')
-rw-r--r--include/clang/AST/Expr.h185
-rw-r--r--include/clang/AST/StmtNodes.def1
-rw-r--r--include/clang/Checker/PathSensitive/GRExprEngine.h4
-rw-r--r--include/clang/Frontend/PCHBitCodes.h2
-rw-r--r--include/clang/Frontend/StmtXML.def9
5 files changed, 198 insertions, 3 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index d824a56acf..2b4d4dfbd2 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -223,7 +223,7 @@ public:
}
/// 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 @@ public:
///
/// __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 @@ public:
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 {
diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def
index 4e80ecbad5..3a23e49148 100644
--- a/include/clang/AST/StmtNodes.def
+++ b/include/clang/AST/StmtNodes.def
@@ -78,6 +78,7 @@ EXPR(StringLiteral , Expr)
EXPR(CharacterLiteral , Expr)
EXPR(ParenExpr , Expr)
EXPR(UnaryOperator , Expr)
+EXPR(OffsetOfExpr , Expr)
EXPR(SizeOfAlignOfExpr , Expr)
EXPR(ArraySubscriptExpr , Expr)
EXPR(CallExpr , Expr)
diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h
index 85c2a6912b..f04ca75084 100644
--- a/include/clang/Checker/PathSensitive/GRExprEngine.h
+++ b/include/clang/Checker/PathSensitive/GRExprEngine.h
@@ -342,6 +342,10 @@ public:
/// 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,
diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h
index 457e63332f..1640afb412 100644
--- a/include/clang/Frontend/PCHBitCodes.h
+++ b/include/clang/Frontend/PCHBitCodes.h
@@ -603,6 +603,8 @@ namespace clang {
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.
diff --git a/include/clang/Frontend/StmtXML.def b/include/clang/Frontend/StmtXML.def
index 2f0da9e7b1..f63761a908 100644
--- a/include/clang/Frontend/StmtXML.def
+++ b/include/clang/Frontend/StmtXML.def
@@ -254,7 +254,7 @@ NODE_XML(UnaryOperator, "UnaryOperator") // op(expr) or (expr)op
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 @@ NODE_XML(ConditionalOperator, "ConditionalOperator") // expr1 ? expr2 : expr3
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())