implement initial sema support for __builtin_offsetof

llvm-svn: 41613
This commit is contained in:
Chris Lattner 2007-08-30 17:45:32 +00:00
parent e4ee2dfcf5
commit f17bd423c2
6 changed files with 107 additions and 21 deletions

View File

@ -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";
}
}

View File

@ -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,

View File

@ -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<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 @@ 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<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 @@ 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,

View File

@ -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);

View File

@ -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. :)

View File

@ -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,