Introduce a single AST node SizeOfAlignOfExpr for all sizeof and alignof expressions, both of values and types.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59057 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/CFG.cpp b/lib/AST/CFG.cpp
index b75ec68..95e1882 100644
--- a/lib/AST/CFG.cpp
+++ b/lib/AST/CFG.cpp
@@ -404,31 +404,23 @@
case Stmt::StmtExprClass:
return WalkAST_VisitStmtExpr(cast<StmtExpr>(Terminator));
- case Stmt::SizeOfAlignOfTypeExprClass: {
- SizeOfAlignOfTypeExpr* E = cast<SizeOfAlignOfTypeExpr>(Terminator);
+ case Stmt::SizeOfAlignOfExprClass: {
+ SizeOfAlignOfExpr* E = cast<SizeOfAlignOfExpr>(Terminator);
// VLA types have expressions that must be evaluated.
- for (VariableArrayType* VA = FindVA(E->getArgumentType().getTypePtr());
- VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
- addStmt(VA->getSizeExpr());
+ if (E->isArgumentType()) {
+ for (VariableArrayType* VA = FindVA(E->getArgumentType().getTypePtr());
+ VA != 0; VA = FindVA(VA->getElementType().getTypePtr()))
+ addStmt(VA->getSizeExpr());
+ }
+ // Expressions in sizeof/alignof are not evaluated and thus have no
+ // control flow.
+ else
+ Block->appendStmt(Terminator);
return Block;
}
- case Stmt::UnaryOperatorClass: {
- UnaryOperator* U = cast<UnaryOperator>(Terminator);
-
- // sizeof(expressions). For such expressions,
- // the subexpression is not really evaluated, so
- // we don't care about control-flow within the sizeof.
- if (U->getOpcode() == UnaryOperator::SizeOf) {
- Block->appendStmt(Terminator);
- return Block;
- }
-
- break;
- }
-
case Stmt::BinaryOperatorClass: {
BinaryOperator* B = cast<BinaryOperator>(Terminator);
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 86a2f29..fbb2256 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -92,8 +92,6 @@
case LNot: return "!";
case Real: return "__real";
case Imag: return "__imag";
- case SizeOf: return "sizeof";
- case AlignOf: return "alignof";
case Extension: return "__extension__";
case OffsetOf: return "__builtin_offsetof";
}
@@ -608,8 +606,7 @@
// Get the operand value. If this is sizeof/alignof, do not evalute the
// operand. This affects C99 6.6p3.
- if (!Exp->isSizeOfAlignOfOp() &&
- Exp->getOpcode() != UnaryOperator::OffsetOf &&
+ if (Exp->getOpcode() != UnaryOperator::OffsetOf &&
!Exp->getSubExpr()->isConstantExpr(Ctx, Loc))
return false;
@@ -621,10 +618,7 @@
return false;
case UnaryOperator::Extension:
return true; // FIXME: this is wrong.
- case UnaryOperator::SizeOf:
- case UnaryOperator::AlignOf:
case UnaryOperator::OffsetOf:
- // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
if (!Exp->getSubExpr()->getType()->isConstantSizeType()) {
if (Loc) *Loc = Exp->getOperatorLoc();
return false;
@@ -637,13 +631,15 @@
return true;
}
}
- case SizeOfAlignOfTypeExprClass: {
- const SizeOfAlignOfTypeExpr *Exp = cast<SizeOfAlignOfTypeExpr>(this);
+ case SizeOfAlignOfExprClass: {
+ const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(this);
// alignof always evaluates to a constant.
- if (Exp->isSizeOf() && !Exp->getArgumentType()->isVoidType() &&
- !Exp->getArgumentType()->isConstantSizeType()) {
- if (Loc) *Loc = Exp->getOperatorLoc();
- return false;
+ if (Exp->isSizeOf()) {
+ QualType ArgTy = Exp->getTypeOfArgument();
+ if (!ArgTy->isVoidType() && !ArgTy->isConstantSizeType()) {
+ if (Loc) *Loc = Exp->getOperatorLoc();
+ return false;
+ }
}
return true;
}
@@ -784,10 +780,10 @@
case UnaryOperatorClass: {
const UnaryOperator *Exp = cast<UnaryOperator>(this);
- // Get the operand value. If this is sizeof/alignof, do not evalute the
+ // Get the operand value. If this is offsetof, do not evalute the
// operand. This affects C99 6.6p3.
- if (!Exp->isSizeOfAlignOfOp() && !Exp->isOffsetOfOp() &&
- !Exp->getSubExpr()->isIntegerConstantExpr(Result, Ctx, Loc,isEvaluated))
+ if (!Exp->isOffsetOfOp() && !Exp->getSubExpr()->
+ isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated))
return false;
switch (Exp->getOpcode()) {
@@ -798,35 +794,6 @@
return false;
case UnaryOperator::Extension:
return true; // FIXME: this is wrong.
- case UnaryOperator::SizeOf:
- case UnaryOperator::AlignOf:
- // Return the result in the right width.
- Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType())));
-
- // sizeof(void) and __alignof__(void) = 1 as a gcc extension.
- if (Exp->getSubExpr()->getType()->isVoidType()) {
- Result = 1;
- break;
- }
-
- // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
- if (!Exp->getSubExpr()->getType()->isConstantSizeType()) {
- if (Loc) *Loc = Exp->getOperatorLoc();
- return false;
- }
-
- // Get information about the size or align.
- if (Exp->getSubExpr()->getType()->isFunctionType()) {
- // GCC extension: sizeof(function) = 1.
- Result = Exp->getOpcode() == UnaryOperator::AlignOf ? 4 : 1;
- } else {
- unsigned CharSize = Ctx.Target.getCharWidth();
- if (Exp->getOpcode() == UnaryOperator::AlignOf)
- Result = Ctx.getTypeAlign(Exp->getSubExpr()->getType()) / CharSize;
- else
- Result = Ctx.getTypeSize(Exp->getSubExpr()->getType()) / CharSize;
- }
- break;
case UnaryOperator::LNot: {
bool Val = Result == 0;
Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType())));
@@ -847,34 +814,35 @@
}
break;
}
- case SizeOfAlignOfTypeExprClass: {
- const SizeOfAlignOfTypeExpr *Exp = cast<SizeOfAlignOfTypeExpr>(this);
+ case SizeOfAlignOfExprClass: {
+ const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(this);
// Return the result in the right width.
Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType())));
+ QualType ArgTy = Exp->getTypeOfArgument();
// sizeof(void) and __alignof__(void) = 1 as a gcc extension.
- if (Exp->getArgumentType()->isVoidType()) {
+ if (ArgTy->isVoidType()) {
Result = 1;
break;
}
// alignof always evaluates to a constant, sizeof does if arg is not VLA.
- if (Exp->isSizeOf() && !Exp->getArgumentType()->isConstantSizeType()) {
+ if (Exp->isSizeOf() && !ArgTy->isConstantSizeType()) {
if (Loc) *Loc = Exp->getOperatorLoc();
return false;
}
// Get information about the size or align.
- if (Exp->getArgumentType()->isFunctionType()) {
+ if (ArgTy->isFunctionType()) {
// GCC extension: sizeof(function) = 1.
Result = Exp->isSizeOf() ? 1 : 4;
} else {
unsigned CharSize = Ctx.Target.getCharWidth();
if (Exp->isSizeOf())
- Result = Ctx.getTypeSize(Exp->getArgumentType()) / CharSize;
+ Result = Ctx.getTypeSize(ArgTy) / CharSize;
else
- Result = Ctx.getTypeAlign(Exp->getArgumentType()) / CharSize;
+ Result = Ctx.getTypeAlign(ArgTy) / CharSize;
}
break;
}
@@ -1280,9 +1248,18 @@
return ::evaluateOffsetOf(C, cast<Expr>(Val)) / CharSize;
}
-void SizeOfAlignOfTypeExpr::Destroy(ASTContext& C) {
- // Override default behavior of traversing children. We do not want
- // to delete the type.
+void SizeOfAlignOfExpr::Destroy(ASTContext& C) {
+ // Override default behavior of traversing children. If this has a type
+ // operand and the type is a variable-length array, the child iteration
+ // will iterate over the size expression. However, this expression belongs
+ // to the type, not to this, so we don't want to delete it.
+ // We still want to delete this expression.
+ // FIXME: Same as in Stmt::Destroy - will be eventually in ASTContext's
+ // pool allocator.
+ if (isArgumentType())
+ delete this;
+ else
+ Expr::Destroy(C);
}
//===----------------------------------------------------------------------===//
@@ -1350,17 +1327,23 @@
Stmt::child_iterator UnaryOperator::child_begin() { return &Val; }
Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; }
-// SizeOfAlignOfTypeExpr
-Stmt::child_iterator SizeOfAlignOfTypeExpr::child_begin() {
- // If the type is a VLA type (and not a typedef), the size expression of the
- // VLA needs to be treated as an executable expression.
- if (VariableArrayType* T = dyn_cast<VariableArrayType>(Ty.getTypePtr()))
- return child_iterator(T);
- else
- return child_iterator();
+// 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
+ // size expression of the VLA needs to be treated as an executable expression.
+ // Why isn't this weirdness documented better in StmtIterator?
+ if (isArgumentType()) {
+ if (VariableArrayType* T = dyn_cast<VariableArrayType>(
+ getArgumentType().getTypePtr()))
+ return child_iterator(T);
+ return child_iterator();
+ }
+ return child_iterator((Stmt**)&Argument);
}
-Stmt::child_iterator SizeOfAlignOfTypeExpr::child_end() {
- return child_iterator();
+Stmt::child_iterator SizeOfAlignOfExpr::child_end() {
+ if (isArgumentType())
+ return child_iterator();
+ return child_iterator((Stmt**)&Argument + 1);
}
// ArraySubscriptExpr
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 1201064..99fa8d5 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -222,14 +222,10 @@
bool VisitCastExpr(CastExpr* E) {
return HandleCast(E->getLocStart(), E->getSubExpr(), E->getType());
}
- bool VisitSizeOfAlignOfTypeExpr(const SizeOfAlignOfTypeExpr *E) {
- return EvaluateSizeAlignOf(E->isSizeOf(), E->getArgumentType(),
- E->getType());
- }
-
+ bool VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
+
private:
bool HandleCast(SourceLocation CastLoc, Expr *SubExpr, QualType DestType);
- bool EvaluateSizeAlignOf(bool isSizeOf, QualType SrcTy, QualType DstTy);
};
} // end anonymous namespace
@@ -426,14 +422,16 @@
return true;
}
-/// EvaluateSizeAlignOf - Evaluate sizeof(SrcTy) or alignof(SrcTy) with a result
-/// as a DstTy type.
-bool IntExprEvaluator::EvaluateSizeAlignOf(bool isSizeOf, QualType SrcTy,
- QualType DstTy) {
+/// VisitSizeAlignOfExpr - Evaluate a sizeof or alignof with a result as the
+/// expression's type.
+bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
+ QualType DstTy = E->getType();
// Return the result in the right width.
Result.zextOrTrunc(getIntTypeSizeInBits(DstTy));
Result.setIsUnsigned(DstTy->isUnsignedIntegerType());
+ QualType SrcTy = E->getTypeOfArgument();
+
// sizeof(void) and __alignof__(void) = 1 as a gcc extension.
if (SrcTy->isVoidType())
Result = 1;
@@ -443,6 +441,8 @@
// FIXME: Should we attempt to evaluate this?
return false;
}
+
+ bool isSizeOf = E->isSizeOf();
// GCC extension: sizeof(function) = 1.
if (SrcTy->isFunctionType()) {
@@ -470,10 +470,6 @@
return true;
}
- if (E->isSizeOfAlignOfOp())
- return EvaluateSizeAlignOf(E->getOpcode() == UnaryOperator::SizeOf,
- E->getSubExpr()->getType(), E->getType());
-
// Get the operand value into 'Result'.
if (!Visit(E->getSubExpr()))
return false;
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index ecfdbf7..0b9e62d 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -119,7 +119,7 @@
void VisitFloatingLiteral(FloatingLiteral *Node);
void VisitStringLiteral(StringLiteral *Str);
void VisitUnaryOperator(UnaryOperator *Node);
- void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node);
+ void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node);
void VisitMemberExpr(MemberExpr *Node);
void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
void VisitBinaryOperator(BinaryOperator *Node);
@@ -363,10 +363,11 @@
fprintf(F, " %s '%s'", Node->isPostfix() ? "postfix" : "prefix",
UnaryOperator::getOpcodeStr(Node->getOpcode()));
}
-void StmtDumper::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) {
+void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
DumpExpr(Node);
fprintf(F, " %s ", Node->isSizeOf() ? "sizeof" : "alignof");
- DumpType(Node->getArgumentType());
+ if (Node->isArgumentType())
+ DumpType(Node->getArgumentType());
}
void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index cc861cc..7529eec 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -620,11 +620,9 @@
if (!Node->isPostfix()) {
OS << UnaryOperator::getOpcodeStr(Node->getOpcode());
- // Print a space if this is an "identifier operator" like sizeof or __real.
+ // Print a space if this is an "identifier operator" like __real.
switch (Node->getOpcode()) {
default: break;
- case UnaryOperator::SizeOf:
- case UnaryOperator::AlignOf:
case UnaryOperator::Real:
case UnaryOperator::Imag:
case UnaryOperator::Extension:
@@ -663,9 +661,14 @@
OS << ")";
}
-void StmtPrinter::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) {
- OS << (Node->isSizeOf() ? "sizeof(" : "__alignof(");
- OS << Node->getArgumentType().getAsString() << ")";
+void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) {
+ OS << (Node->isSizeOf() ? "sizeof" : "__alignof");
+ if (Node->isArgumentType())
+ OS << "(" << Node->getArgumentType().getAsString() << ")";
+ else {
+ OS << " ";
+ PrintExpr(Node->getArgumentExpr());
+ }
}
void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
PrintExpr(Node->getLHS());
diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp
index 3982881..f71b88b 100644
--- a/lib/AST/StmtSerialization.cpp
+++ b/lib/AST/StmtSerialization.cpp
@@ -136,8 +136,8 @@
case ReturnStmtClass:
return ReturnStmt::CreateImpl(D, C);
- case SizeOfAlignOfTypeExprClass:
- return SizeOfAlignOfTypeExpr::CreateImpl(D, C);
+ case SizeOfAlignOfExprClass:
+ return SizeOfAlignOfExpr::CreateImpl(D, C);
case StmtExprClass:
return StmtExpr::CreateImpl(D, C);
@@ -795,22 +795,33 @@
return new ReturnStmt(RetLoc,RetExpr);
}
-void SizeOfAlignOfTypeExpr::EmitImpl(Serializer& S) const {
+void SizeOfAlignOfExpr::EmitImpl(Serializer& S) const {
S.EmitBool(isSizeof);
- S.Emit(Ty);
+ S.EmitBool(isType);
+ if (isType)
+ S.Emit(getArgumentType());
+ else
+ S.EmitOwnedPtr(getArgumentExpr());
S.Emit(getType());
S.Emit(OpLoc);
S.Emit(RParenLoc);
}
-SizeOfAlignOfTypeExpr* SizeOfAlignOfTypeExpr::CreateImpl(Deserializer& D, ASTContext& C) {
+SizeOfAlignOfExpr*
+SizeOfAlignOfExpr::CreateImpl(Deserializer& D, ASTContext& C) {
bool isSizeof = D.ReadBool();
- QualType Ty = QualType::ReadVal(D);
+ bool isType = D.ReadBool();
+ void *Argument;
+ if (isType)
+ Argument = QualType::ReadVal(D).getAsOpaquePtr();
+ else
+ Argument = D.ReadOwnedPtr<Expr>(C);
QualType Res = QualType::ReadVal(D);
SourceLocation OpLoc = SourceLocation::ReadVal(D);
SourceLocation RParenLoc = SourceLocation::ReadVal(D);
- return new SizeOfAlignOfTypeExpr(isSizeof,Ty,Res,OpLoc,RParenLoc);
+ return new SizeOfAlignOfExpr(isSizeof, isType, Argument, Res,
+ OpLoc, RParenLoc);
}
void StmtExpr::EmitImpl(Serializer& S) const {