diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-04-28 22:16:22 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-04-28 22:16:22 +0000 |
commit | 8ecdb65716cd7914ffb2eeee993fa9039fcd31e8 (patch) | |
tree | cba751b09dbf3a8fe4aa9114a7d7880095b9d199 | |
parent | 109dfc6ca6652f60c55ed0f2631aebf323d0200d (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
-rw-r--r-- | include/clang/AST/Expr.h | 185 | ||||
-rw-r--r-- | include/clang/AST/StmtNodes.def | 1 | ||||
-rw-r--r-- | include/clang/Checker/PathSensitive/GRExprEngine.h | 4 | ||||
-rw-r--r-- | include/clang/Frontend/PCHBitCodes.h | 2 | ||||
-rw-r--r-- | include/clang/Frontend/StmtXML.def | 9 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 67 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 66 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 30 | ||||
-rw-r--r-- | lib/AST/StmtProfile.cpp | 24 | ||||
-rw-r--r-- | lib/Checker/GRExprEngine.cpp | 37 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 18 | ||||
-rw-r--r-- | lib/Frontend/PCHReaderStmt.cpp | 45 | ||||
-rw-r--r-- | lib/Frontend/PCHWriterStmt.cpp | 32 | ||||
-rw-r--r-- | lib/Frontend/StmtXML.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 5 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 205 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 71 | ||||
-rw-r--r-- | test/PCH/exprs.c | 4 | ||||
-rw-r--r-- | test/PCH/exprs.h | 13 | ||||
-rw-r--r-- | test/SemaCXX/offsetof.cpp | 10 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-expr-5.cpp | 20 | ||||
-rw-r--r-- | tools/CIndex/CIndex.cpp | 9 | ||||
-rw-r--r-- | tools/CIndex/CXCursor.cpp | 3 |
24 files changed, 815 insertions, 54 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()) 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 diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index a52cf6fe4c..7233518d58 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -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 @@ public: 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 @@ public: 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 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { 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 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { // 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; diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 3996528287..b50bb0ce7e 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -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 @@ void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) { 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()) diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 3a19ec212c..3d528f3ccb 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -261,6 +261,30 @@ void StmtProfiler::VisitUnaryOperator(UnaryOperator *S) { 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()); diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp index c11a16ff7b..67090b8669 100644 --- a/lib/Checker/GRExprEngine.cpp +++ b/lib/Checker/GRExprEngine.cpp @@ -823,6 +823,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) { 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 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, 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 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred, 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: { diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 842590b24c..9849688023 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -133,6 +133,7 @@ public: 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 @@ public: return Visit(E->getSubExpr()); } Value *VisitUnaryOffsetOf(const UnaryOperator *E); - + // C++ Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { return Visit(DAE->getExpr()); @@ -1030,6 +1031,21 @@ Value *ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) { 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 * diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp index 5e08be138a..8588c8aa1a 100644 --- a/lib/Frontend/PCHReaderStmt.cpp +++ b/lib/Frontend/PCHReaderStmt.cpp @@ -71,6 +71,7 @@ namespace { 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 @@ unsigned PCHStmtReader::VisitUnaryOperator(UnaryOperator *E) { 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(); |