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 {