// Get the operand value. If this is sizeof/alignof, do not evalute the
// operand. This affects C99 6.6p3.
- if (!Exp->isSizeOfAlignOfOp() &&
+ if (!Exp->isSizeOfAlignOfOp() && !Exp->isOffsetOfOp() &&
!Exp->getSubExpr()->isIntegerConstantExpr(Result, Ctx, Loc,isEvaluated))
return false;
case UnaryOperator::Not:
Result = ~Result;
break;
+ case UnaryOperator::OffsetOf:
+ Result = Exp->evaluateOffsetOf(Ctx);
}
break;
}
return CondVal != 0;
}
+static int64_t evaluateOffsetOf(ASTContext& C, const Expr *E)
+{
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ QualType Ty = ME->getBase()->getType();
+
+ RecordDecl *RD = Ty->getAsRecordType()->getDecl();
+ const ASTRecordLayout &RL = C.getASTRecordLayout(RD, SourceLocation());
+ FieldDecl *FD = ME->getMemberDecl();
+
+ // FIXME: This is linear time.
+ unsigned i = 0, e = 0;
+ for (i = 0, e = RD->getNumMembers(); i != e; i++) {
+ if (RD->getMember(i) == FD)
+ break;
+ }
+
+ return RL.getFieldOffset(i) + evaluateOffsetOf(C, ME->getBase());
+ } else if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
+ const Expr *Base = ASE->getBase();
+ llvm::APSInt Idx(32);
+ bool ICE = ASE->getIdx()->isIntegerConstantExpr(Idx, C);
+ assert(ICE && "Array index is not a constant integer!");
+
+ int64_t size = C.getTypeSize(ASE->getType(), SourceLocation());
+ size *= Idx.getSExtValue();
+
+ return size + evaluateOffsetOf(C, Base);
+ } else if (isa<CompoundLiteralExpr>(E))
+ return 0;
+
+ assert(0 && "Unknown offsetof subexpression!");
+ return 0;
+}
+
+int64_t UnaryOperator::evaluateOffsetOf(ASTContext& C) const
+{
+ assert(Opc == OffsetOf && "Unary operator not offsetof!");
+
+ unsigned CharSize =
+ C.Target.getCharWidth(C.getFullLoc(getOperatorLoc()));
+
+ return ::evaluateOffsetOf(C, Val) / CharSize;
+}
+
//===----------------------------------------------------------------------===//
// Child Iterators for iterating over subexpressions/substatements
//===----------------------------------------------------------------------===//
llvm::Constant *VisitUnaryAddrOf(const UnaryOperator *E) {
return EmitLValue(E->getSubExpr());
}
+ llvm::Constant *VisitUnaryOffsetOf(const UnaryOperator *E) {
+ int64_t Val = E->evaluateOffsetOf(CGM.getContext());
+
+ assert(E->getType()->isIntegerType() && "Result type must be an integer!");
+
+ uint32_t ResultWidth = static_cast<uint32_t>(
+ CGM.getContext().getTypeSize(E->getType(), SourceLocation()));
+ return llvm::ConstantInt::get(llvm::APInt(ResultWidth, Val));
+ }
// Binary operators
llvm::Constant *VisitBinOr(const BinaryOperator *E) {
Value *VisitUnaryExtension(const UnaryOperator *E) {
return Visit(E->getSubExpr());
}
-
+ Value *VisitUnaryOffsetOf(const UnaryOperator *E);
+
// Binary Operators.
Value *EmitMul(const BinOpInfo &Ops) {
return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul");
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
+Value *ScalarExprEmitter::VisitUnaryOffsetOf(const UnaryOperator *E)
+{
+ int64_t Val = E->evaluateOffsetOf(CGF.getContext());
+
+ assert(E->getType()->isIntegerType() && "Result type must be an integer!");
+
+ uint32_t ResultWidth = static_cast<uint32_t>(
+ CGF.getContext().getTypeSize(E->getType(), SourceLocation()));
+ return llvm::ConstantInt::get(llvm::APInt(ResultWidth, Val));
+}
//===----------------------------------------------------------------------===//
// Binary Operators
bool isPostfix() const { return isPostfix(Opc); }
bool isIncrementDecrementOp() const { return Opc>=PostInc && Opc<=PreDec; }
bool isSizeOfAlignOfOp() const { return Opc == SizeOf || Opc == AlignOf; }
+ bool isOffsetOfOp() const { return Opc == OffsetOf; }
static bool isArithmeticOp(Opcode Op) { return Op >= Plus && Op <= LNot; }
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
}
static bool classof(const UnaryOperator *) { return true; }
+ int64_t evaluateOffsetOf(ASTContext& C) const;
+
// Iterators
virtual child_iterator child_begin();
virtual child_iterator child_end();
x = __builtin_offsetof(struct external_sun3_core, X[42].f2); // expected-error {{no member named 'f2'}}
x = __builtin_offsetof(int, X[42].f2); // expected-error {{offsetof requires struct}}
+
+ int a[__builtin_offsetof(struct external_sun3_core, X) == 4 ? 1 : -1];
+ int b[__builtin_offsetof(struct external_sun3_core, X[42]) == 340 ? 1 : -1];
+ int c[__builtin_offsetof(struct external_sun3_core, X[42].f2) == 344 ? 1 : -1];
}