From 73d0d4fac161ed12926e010dcf8b448a8de6a2ec Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Thu, 30 Aug 2007 17:45:32 +0000 Subject: [PATCH] implement initial sema support for __builtin_offsetof git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41613 91177308-0d34-0410-b5e6-96231b3b80d8 --- AST/Expr.cpp | 1 + Sema/Sema.h | 9 ++- Sema/SemaExpr.cpp | 83 ++++++++++++++++++++++--- include/clang/AST/Expr.h | 27 +++++--- include/clang/AST/StmtVisitor.h | 3 +- include/clang/Basic/DiagnosticKinds.def | 5 ++ 6 files changed, 107 insertions(+), 21 deletions(-) diff --git a/AST/Expr.cpp b/AST/Expr.cpp index 0b284a8a3f..3aed116c76 100644 --- a/AST/Expr.cpp +++ b/AST/Expr.cpp @@ -69,6 +69,7 @@ const char *UnaryOperator::getOpcodeStr(Opcode Op) { case SizeOf: return "sizeof"; case AlignOf: return "alignof"; case Extension: return "__extension__"; + case OffsetOf: return "__builtin_offsetof"; } } diff --git a/Sema/Sema.h b/Sema/Sema.h index 2c496a76cd..fbf4f53be1 100644 --- a/Sema/Sema.h +++ b/Sema/Sema.h @@ -306,7 +306,14 @@ public: virtual ExprResult ParseStmtExpr(SourceLocation LPLoc, StmtTy *SubStmt, SourceLocation RPLoc); // "({..})" - + + /// __builtin_offsetof(type, a.b[123][456].c) + virtual ExprResult ParseBuiltinOffsetOf(SourceLocation BuiltinLoc, + SourceLocation TypeLoc, TypeTy *Arg1, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RParenLoc); + // __builtin_types_compatible_p(type1, type2) virtual ExprResult ParseTypesCompatibleExpr(SourceLocation BuiltinLoc, TypeTy *arg1, TypeTy *arg2, diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp index 1ddbccb7e9..2d048bd475 100644 --- a/Sema/SemaExpr.cpp +++ b/Sema/SemaExpr.cpp @@ -334,7 +334,7 @@ ParseArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc, QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType(); // C99 6.5.2.1p2: the expression e1[e2] is by definition precisely equivalent - // to the expression *((e1)+(e2)). This means the array "Base" may actually be + // to the expression *((e1)+(e2)). This means the array "Base" may actually be // in the subscript position. As a result, we need to derive the array base // and index from the expression types. Expr *BaseExpr, *IndexExpr; @@ -619,7 +619,8 @@ ParseCallExpr(ExprTy *fn, SourceLocation LParenLoc, if (ImplicitCastExpr *IcExpr = dyn_cast(Fn)) if (DeclRefExpr *DRExpr = dyn_cast(IcExpr->getSubExpr())) if (FunctionDecl *FDecl = dyn_cast(DRExpr->getDecl())) - if (CheckFunctionCall(Fn, LParenLoc, RParenLoc, FDecl, Args, NumArgsInCall)) + if (CheckFunctionCall(Fn, LParenLoc, RParenLoc, FDecl, Args, + NumArgsInCall)) return true; return new CallExpr(Fn, Args, NumArgsInCall, resultType, RParenLoc); @@ -693,7 +694,7 @@ inline QualType Sema::CheckConditionalOperands( // C99 6.5.15 if (const RecordType *LHSRT = lexT->getAsRecordType()) { // C99 6.5.15p3 if (const RecordType *RHSRT = rexT->getAsRecordType()) { - if (LHSRT->getDecl()->getIdentifier() ==RHSRT->getDecl()->getIdentifier()) + if (LHSRT->getDecl()->getIdentifier() ==RHSRT->getDecl()->getIdentifier()) return lexT; Diag(questionLoc, diag::err_typecheck_cond_incompatible_operands, @@ -730,9 +731,10 @@ inline QualType Sema::CheckConditionalOperands( // C99 6.5.15 return lexT; // FIXME: this is an _ext - is this return o.k? } // The pointer types are compatible. - // C99 6.5.15p6: If both operands are pointers to compatible types *or* to - // differently qualified versions of compatible types, the result type is a - // pointer to an appropriately qualified version of the *composite* type. + // C99 6.5.15p6: If both operands are pointers to compatible types *or* to + // differently qualified versions of compatible types, the result type is + // a pointer to an appropriately qualified version of the *composite* + // type. return lexT; // FIXME: Need to return the composite type. } } @@ -818,7 +820,7 @@ void Sema::UsualUnaryConversions(Expr *&expr) { DefaultFunctionArrayConversion(expr); } -/// UsualArithmeticConversions - Performs various conversions that are common to +/// UsualArithmeticConversions - Performs various conversions that are common to /// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this /// routine returns the first non-arithmetic type found. The client is /// responsible for emitting appropriate error diagnostics. @@ -1315,7 +1317,8 @@ inline QualType Sema::CheckAssignmentOperands( // C99 6.5.16.1 // it is the unqualified version of the type of the left operand. // C99 6.5.16.1p2: In simple assignment, the value of the right operand // is converted to the type of the assignment expression (above). - // C++ 5.17p1: the type of the assignment expression is that of its left oprdu. + // C++ 5.17p1: the type of the assignment expression is that of its left + // oprdu. return hadError ? QualType() : lhsType.getUnqualifiedType(); } @@ -1715,6 +1718,68 @@ Sema::ExprResult Sema::ParseStmtExpr(SourceLocation LPLoc, StmtTy *substmt, return new StmtExpr(Compound, Ty, LPLoc, RPLoc); } +Sema::ExprResult Sema::ParseBuiltinOffsetOf(SourceLocation BuiltinLoc, + SourceLocation TypeLoc, + TypeTy *argty, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RPLoc) { + QualType ArgTy = QualType::getFromOpaquePtr(argty); + assert(!ArgTy.isNull() && "Missing type argument!"); + + // 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 (!ArgTy->isRecordType()) + return Diag(TypeLoc, diag::err_offsetof_record_type,ArgTy.getAsString()); + + // Otherwise, create a compound literal expression as the base, and + // iteratively process the offsetof designators. + Expr *Res = new CompoundLiteralExpr(ArgTy, 0); + + 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? + const ArrayType *AT = Res->getType()->getAsArrayType(); + if (!AT) { + delete Res; + return Diag(OC.LocEnd, diag::err_offsetof_array_type, + Res->getType().getAsString()); + } + + // C99 6.5.2.1p1 + Expr *Idx = static_cast(OC.U.E); + if (!Idx->getType()->isIntegerType()) + return Diag(Idx->getLocStart(), diag::err_typecheck_subscript, + Idx->getSourceRange()); + + Res = new ArraySubscriptExpr(Res, Idx, AT->getElementType(), OC.LocEnd); + continue; + } + + const RecordType *RC = Res->getType()->getAsRecordType(); + if (!RC) { + delete Res; + return Diag(OC.LocEnd, diag::err_offsetof_record_type, + Res->getType().getAsString()); + } + + // Get the decl corresponding to this. + RecordDecl *RD = RC->getDecl(); + FieldDecl *MemberDecl = RD->getMember(OC.U.IdentInfo); + if (!MemberDecl) + return Diag(BuiltinLoc, diag::err_typecheck_no_member, + OC.U.IdentInfo->getName(), + SourceRange(OC.LocStart, OC.LocEnd)); + Res = new MemberExpr(Res, false, MemberDecl, OC.LocEnd); + } + + return new UnaryOperator(Res, UnaryOperator::OffsetOf, Context.getSizeType(), + BuiltinLoc); +} + + Sema::ExprResult Sema::ParseTypesCompatibleExpr(SourceLocation BuiltinLoc, TypeTy *arg1, TypeTy *arg2, SourceLocation RPLoc) { @@ -1723,7 +1788,7 @@ Sema::ExprResult Sema::ParseTypesCompatibleExpr(SourceLocation BuiltinLoc, assert((!argT1.isNull() && !argT2.isNull()) && "Missing type argument(s)"); - return new TypesCompatibleExpr(Context.IntTy, BuiltinLoc, argT1, argT2, RPLoc); + return new TypesCompatibleExpr(Context.IntTy, BuiltinLoc, argT1, argT2,RPLoc); } Sema::ExprResult Sema::ParseChooseExpr(SourceLocation BuiltinLoc, ExprTy *cond, diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 138db62cf9..375252c6c9 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -32,7 +32,6 @@ class Expr : public Stmt { QualType TR; protected: Expr(StmtClass SC, QualType T) : Stmt(SC), TR(T) {} - ~Expr() {} public: QualType getType() const { return TR; } void setType(QualType t) { TR = t; } @@ -329,6 +328,10 @@ public: /// applied to a non-complex value, the former returns its operand and the /// later returns zero in the type of the operand. /// +/// __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. +/// class UnaryOperator : public Expr { public: // Note that additions to this should also update the StmtVisitor class. @@ -340,7 +343,8 @@ public: Not, LNot, // [C99 6.5.3.3] Unary arithmetic operators. SizeOf, AlignOf, // [C99 6.5.3.4] Sizeof (expr, not type) operator. Real, Imag, // "__real expr"/"__imag expr" Extension. - Extension // __extension__ marker. + Extension, // __extension__ marker. + OffsetOf // __builtin_offsetof }; private: Expr *Val; @@ -431,12 +435,11 @@ class ArraySubscriptExpr : public Expr { SourceLocation RBracketLoc; public: ArraySubscriptExpr(Expr *lhs, Expr *rhs, QualType t, - SourceLocation rbracketloc) : - Expr(ArraySubscriptExprClass, t), - RBracketLoc(rbracketloc) { - SubExprs[LHS] = lhs; - SubExprs[RHS] = rhs; - } + SourceLocation rbracketloc) + : Expr(ArraySubscriptExprClass, t), RBracketLoc(rbracketloc) { + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + } /// An array access can be written A[4] or 4[A] (both are equivalent). /// - getBase() and getIdx() always present the normalized view: A[4]. @@ -636,7 +639,11 @@ public: const Expr *getInitializer() const { return Init; } Expr *getInitializer() { return Init; } - virtual SourceRange getSourceRange() const { return Init->getSourceRange(); } + virtual SourceRange getSourceRange() const { + if (Init) + return Init->getSourceRange(); + return SourceRange(); + } static bool classof(const Stmt *T) { return T->getStmtClass() == CompoundLiteralExprClass; @@ -908,7 +915,7 @@ public: QualType getArgType1() const { return Type1; } QualType getArgType2() const { return Type2; } - int typesAreCompatible() const { return Type::typesAreCompatible(Type1,Type2); } + int typesAreCompatible() const {return Type::typesAreCompatible(Type1,Type2);} virtual SourceRange getSourceRange() const { return SourceRange(BuiltinLoc, RParenLoc); diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h index 1c252965bd..c8ebbf2651 100644 --- a/include/clang/AST/StmtVisitor.h +++ b/include/clang/AST/StmtVisitor.h @@ -95,6 +95,7 @@ public: case UnaryOperator::Real: DISPATCH(UnaryReal, UnaryOperator); case UnaryOperator::Imag: DISPATCH(UnaryImag, UnaryOperator); case UnaryOperator::Extension: DISPATCH(UnaryExtension, UnaryOperator); + case UnaryOperator::OffsetOf: DISPATCH(UnaryExtension, UnaryOperator); } } @@ -158,7 +159,7 @@ public: UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot) UNARYOP_FALLBACK(SizeOf) UNARYOP_FALLBACK(AlignOf) UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag) - UNARYOP_FALLBACK(Extension) + UNARYOP_FALLBACK(Extension) UNARYOP_FALLBACK(OffsetOf) #undef UNARYOP_FALLBACK // Base case, ignore it. :) diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 8b1b1430e7..dbfa1e6f9e 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -581,6 +581,11 @@ DIAG(err_sizeof_incomplete_type, ERROR, "invalid application of 'sizeof' to an incomplete type '%0'") DIAG(err_alignof_incomplete_type, ERROR, "invalid application of '__alignof' to an incomplete type '%0'") +DIAG(err_offsetof_record_type, ERROR, + "offsetof requires struct, union, or class type, '%0' invalid") +DIAG(err_offsetof_array_type, ERROR, + "offsetof requires array type, '%0' invalid") + DIAG(err_invalid_suffix_integer_constant, ERROR, "invalid suffix '%0' on integer constant") DIAG(err_invalid_suffix_float_constant, ERROR, -- 2.40.0