aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/Expr.cpp
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 /lib/AST/Expr.cpp
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 'lib/AST/Expr.cpp')
-rw-r--r--lib/AST/Expr.cpp67
1 files changed, 64 insertions, 3 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 8770bfd3aa..308f6b4dc0 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -549,6 +549,57 @@ QualType CallExpr::getCallReturnType() const {
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 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
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 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
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 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// 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 ParenExpr::child_end() { return &Val+1; }
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