implement initial sema support for __builtin_offsetof
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41613 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/AST/Expr.cpp b/AST/Expr.cpp
index 0b284a8..3aed116 100644
--- a/AST/Expr.cpp
+++ b/AST/Expr.cpp
@@ -69,6 +69,7 @@
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 2c496a7..fbf4f53 100644
--- a/Sema/Sema.h
+++ b/Sema/Sema.h
@@ -306,7 +306,14 @@
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 1ddbccb..2d048bd 100644
--- a/Sema/SemaExpr.cpp
+++ b/Sema/SemaExpr.cpp
@@ -334,7 +334,7 @@
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 @@
if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(Fn))
if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(IcExpr->getSubExpr()))
if (FunctionDecl *FDecl = dyn_cast<FunctionDecl>(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 @@
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 @@
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 @@
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 @@
// 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 @@
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<Expr*>(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 @@
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 138db62..375252c 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -32,7 +32,6 @@
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 @@
/// 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 @@
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 @@
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 @@
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 @@
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 1c25296..c8ebbf2 100644
--- a/include/clang/AST/StmtVisitor.h
+++ b/include/clang/AST/StmtVisitor.h
@@ -95,6 +95,7 @@
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 @@
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 8b1b143..dbfa1e6 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -581,6 +581,11 @@
"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,