riccibruno created this revision.
riccibruno added a reviewer: rjmccall.
riccibruno added a project: clang.
Herald added subscribers: cfe-commits, javed.absar.
riccibruno added a dependency: D53605: [AST] Pack PredefinedExpr.

Only store the needed data in `IfStmt`. The various `Stmt *` are put in
a trailing array with the commonly used `Stmt *` first (like the condition
and the then statement) and the less commonly used `Stmt *` last.
This cuts the size of `IfStmt` by up to 3 pointers + 1 `SourceLocation`.

One point which must be discussed is that this changes the order of the
children. This is strictly speaking not needed (we could just compute the
appropriate index into the trailing array) but this allows the common data
to be at a constant offset into the trailing array. This saves us from doing
bit manipulations and arithmetic each time the commonly used data is accessed.

I believe the C API is unaffected since it do not rely on calling `children` on 
`IfStmt`.
This also makes modifying an `IfStmt` after creation harder since the necessary
storage might not exist.


Repository:
  rC Clang

https://reviews.llvm.org/D53607

Files:
  include/clang/AST/Stmt.h
  lib/AST/ASTImporter.cpp
  lib/AST/Stmt.cpp
  lib/Analysis/BodyFarm.cpp
  lib/Sema/SemaStmt.cpp
  lib/Serialization/ASTReaderStmt.cpp
  lib/Serialization/ASTWriterStmt.cpp
  test/Import/if-stmt/test.cpp
  test/Misc/ast-dump-invalid.cpp

Index: test/Misc/ast-dump-invalid.cpp
===================================================================
--- test/Misc/ast-dump-invalid.cpp
+++ test/Misc/ast-dump-invalid.cpp
@@ -33,8 +33,6 @@
 // CHECK-NEXT:   |-ParmVarDecl
 // CHECK-NEXT:   `-CompoundStmt
 // CHECK-NEXT:     `-IfStmt {{.*}} <line:25:3, line:28:12>
-// CHECK-NEXT:       |-<<<NULL>>>
-// CHECK-NEXT:       |-<<<NULL>>>
 // CHECK-NEXT:       |-OpaqueValueExpr {{.*}} <<invalid sloc>> 'bool'
 // CHECK-NEXT:       |-ReturnStmt {{.*}} <line:26:5, col:12>
 // CHECK-NEXT:       | `-IntegerLiteral {{.*}} <col:12> 'int' 4
@@ -50,15 +48,15 @@
 { return 45; }
 }
 // CHECK: NamespaceDecl {{.*}} <{{.*}}> {{.*}} TestInvalidFunctionDecl
-// CHECK-NEXT: |-CXXRecordDecl {{.*}} <line:46:1, line:48:1> line:46:8 struct Str definition
+// CHECK-NEXT: |-CXXRecordDecl {{.*}} <line:44:1, line:46:1> line:44:8 struct Str definition
 // CHECK:      | |-CXXRecordDecl {{.*}} <col:1, col:8> col:8 implicit struct Str
-// CHECK-NEXT: | `-CXXMethodDecl {{.*}} <line:47:4, col:36> col:11 invalid foo1 'double (double, int)'
+// CHECK-NEXT: | `-CXXMethodDecl {{.*}} <line:45:4, col:36> col:11 invalid foo1 'double (double, int)'
 // CHECK-NEXT: |   |-ParmVarDecl {{.*}} <col:16> col:22 'double'
 // CHECK-NEXT: |   `-ParmVarDecl {{.*}} <col:24, <invalid sloc>> col:36 invalid 'int'
-// CHECK-NEXT: `-CXXMethodDecl {{.*}} parent {{.*}} <line:49:1, line:50:14> line:49:13 invalid foo1 'double (double, int)'
+// CHECK-NEXT: `-CXXMethodDecl {{.*}} parent {{.*}} <line:47:1, line:48:14> line:47:13 invalid foo1 'double (double, int)'
 // CHECK-NEXT:   |-ParmVarDecl {{.*}} <col:18> col:24 'double'
 // CHECK-NEXT:   |-ParmVarDecl {{.*}} <col:26, <invalid sloc>> col:38 invalid 'int'
-// CHECK-NEXT:   `-CompoundStmt {{.*}} <line:50:1, col:14>
+// CHECK-NEXT:   `-CompoundStmt {{.*}} <line:48:1, col:14>
 // CHECK-NEXT:     `-ReturnStmt {{.*}} <col:3, col:10>
 // CHECK-NEXT:       `-ImplicitCastExpr {{.*}} <col:10> 'double' <IntegralToFloating>
 // CHECK-NEXT:         `-IntegerLiteral {{.*}} <col:10> 'int' 45
Index: test/Import/if-stmt/test.cpp
===================================================================
--- test/Import/if-stmt/test.cpp
+++ test/Import/if-stmt/test.cpp
@@ -1,41 +1,30 @@
 // RUN: clang-import-test -dump-ast -import %S/Inputs/F.cpp -expression %s | FileCheck %s
 
 // CHECK: IfStmt
-// CHECK-NEXT: <<NULL>>
-// CHECK-NEXT: <<NULL>>
 // CHECK-NEXT: CXXBoolLiteralExpr
 // CHECK-NEXT: ReturnStmt
-// CHECK-NEXT: <<NULL>>
 
 // CHECK: IfStmt
-// CHECK-NEXT: <<NULL>>
-// CHECK-NEXT: DeclStmt
-// CHECK-NEXT: VarDecl
-// CHECK-NEXT: IntegerLiteral
 // CHECK-NEXT: ImplicitCastExpr
 // CHECK-NEXT: ImplicitCastExpr
 // CHECK-NEXT: DeclRefExpr
 // CHECK-NEXT: ReturnStmt
-// CHECK-NEXT: <<NULL>>
-
-// CHECK: IfStmt
 // CHECK-NEXT: DeclStmt
 // CHECK-NEXT: VarDecl
-// CHECK-NEXT: <<NULL>>
+// CHECK-NEXT: IntegerLiteral
+
+// CHECK: IfStmt
 // CHECK-NEXT: CXXBoolLiteralExpr
 // CHECK-NEXT: ReturnStmt
-// CHECK-NEXT: <<NULL>>
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl
 
 // CHECK: IfStmt
-// CHECK-NEXT: <<NULL>>
-// CHECK-NEXT: <<NULL>>
 // CHECK-NEXT: CXXBoolLiteralExpr
 // CHECK-NEXT: ReturnStmt
 // CHECK-NEXT: ReturnStmt
 
 // CHECK: IfStmt
-// CHECK-NEXT: <<NULL>>
-// CHECK-NEXT: <<NULL>>
 // CHECK-NEXT: CXXBoolLiteralExpr
 // CHECK-NEXT: CompoundStmt
 // CHECK-NEXT: ReturnStmt
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -128,14 +128,29 @@
 
 void ASTStmtWriter::VisitIfStmt(IfStmt *S) {
   VisitStmt(S);
+
+  bool HasElse = !!S->getElse();
+  bool HasVar = !!S->getConditionVariableDeclStmt();
+  bool HasInit = !!S->getInit();
+
   Record.push_back(S->isConstexpr());
-  Record.AddStmt(S->getInit());
-  Record.AddDeclRef(S->getConditionVariable());
+  Record.push_back(HasElse);
+  Record.push_back(HasVar);
+  Record.push_back(HasInit);
+
   Record.AddStmt(S->getCond());
   Record.AddStmt(S->getThen());
-  Record.AddStmt(S->getElse());
+  if (HasElse)
+    Record.AddStmt(S->getElse());
+  if (HasVar)
+    Record.AddDeclRef(S->getConditionVariable());
+  if (HasInit)
+    Record.AddStmt(S->getInit());
+
   Record.AddSourceLocation(S->getIfLoc());
-  Record.AddSourceLocation(S->getElseLoc());
+  if (HasElse)
+    Record.AddSourceLocation(S->getElseLoc());
+
   Code = serialization::STMT_IF;
 }
 
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -215,14 +215,24 @@
 
 void ASTStmtReader::VisitIfStmt(IfStmt *S) {
   VisitStmt(S);
+
   S->setConstexpr(Record.readInt());
-  S->setInit(Record.readSubStmt());
-  S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>());
+  bool HasElse = Record.readInt();
+  bool HasVar = Record.readInt();
+  bool HasInit = Record.readInt();
+
   S->setCond(Record.readSubExpr());
   S->setThen(Record.readSubStmt());
-  S->setElse(Record.readSubStmt());
+  if (HasElse)
+    S->setElse(Record.readSubStmt());
+  if (HasVar)
+    S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>());
+  if (HasInit)
+    S->setInit(Record.readSubStmt());
+
   S->setIfLoc(ReadSourceLocation());
-  S->setElseLoc(ReadSourceLocation());
+  if (HasElse)
+    S->setElseLoc(ReadSourceLocation());
 }
 
 void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) {
@@ -2285,7 +2295,11 @@
       break;
 
     case STMT_IF:
-      S = new (Context) IfStmt(Empty);
+      S = IfStmt::CreateEmpty(
+          Context,
+          /* HasElse=*/Record[ASTStmtReader::NumStmtFields + 1],
+          /* HasVar=*/Record[ASTStmtReader::NumStmtFields + 2],
+          /* HasInit=*/Record[ASTStmtReader::NumStmtFields + 3]);
       break;
 
     case STMT_SWITCH:
Index: lib/Sema/SemaStmt.cpp
===================================================================
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -576,9 +576,8 @@
   DiagnoseUnusedExprResult(thenStmt);
   DiagnoseUnusedExprResult(elseStmt);
 
-  return new (Context)
-      IfStmt(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first,
-             Cond.get().second, thenStmt, ElseLoc, elseStmt);
+  return IfStmt::Create(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first,
+                        Cond.get().second, thenStmt, ElseLoc, elseStmt);
 }
 
 namespace {
Index: lib/Analysis/BodyFarm.cpp
===================================================================
--- lib/Analysis/BodyFarm.cpp
+++ lib/Analysis/BodyFarm.cpp
@@ -464,13 +464,13 @@
       Deref, M.makeIntegralCast(M.makeIntegerLiteral(1, C.IntTy), DerefType),
       DerefType);
 
-  IfStmt *Out = new (C)
-      IfStmt(C, SourceLocation(),
-             /* IsConstexpr=*/ false,
-             /* init=*/ nullptr,
-             /* var=*/ nullptr,
-             /* cond=*/ FlagCheck,
-             /* then=*/ M.makeCompound({CallbackCall, FlagAssignment}));
+  auto *Out =
+      IfStmt::Create(C, SourceLocation(),
+                     /* IsConstexpr=*/false,
+                     /* init=*/nullptr,
+                     /* var=*/nullptr,
+                     /* cond=*/FlagCheck,
+                     /* then=*/M.makeCompound({CallbackCall, FlagAssignment}));
 
   return Out;
 }
@@ -549,12 +549,12 @@
 
   Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE);
   // (5) Create the 'if' statement.
-  IfStmt *If = new (C) IfStmt(C, SourceLocation(),
-                              /* IsConstexpr=*/ false,
-                              /* init=*/ nullptr,
-                              /* var=*/ nullptr,
-                              /* cond=*/ GuardCondition,
-                              /* then=*/ CS);
+  auto *If = IfStmt::Create(C, SourceLocation(),
+                            /* IsConstexpr=*/false,
+                            /* init=*/nullptr,
+                            /* var=*/nullptr,
+                            /* cond=*/GuardCondition,
+                            /* then=*/CS);
   return If;
 }
 
@@ -657,8 +657,11 @@
   Stmt *Else = M.makeReturn(RetVal);
 
   /// Construct the If.
-  Stmt *If = new (C) IfStmt(C, SourceLocation(), false, nullptr, nullptr,
-                            Comparison, Body, SourceLocation(), Else);
+  auto *If = IfStmt::Create(C, SourceLocation(),
+                            /* IsConstexpr=*/false,
+                            /* init=*/nullptr,
+                            /* var=*/nullptr, Comparison, Body,
+                            SourceLocation(), Else);
 
   return If;
 }
Index: lib/AST/Stmt.cpp
===================================================================
--- lib/AST/Stmt.cpp
+++ lib/AST/Stmt.cpp
@@ -800,38 +800,85 @@
 }
 
 IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, bool IsConstexpr,
-               Stmt *init, VarDecl *var, Expr *cond, Stmt *then,
-               SourceLocation EL, Stmt *elsev)
-    : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) {
+               Stmt *Init, VarDecl *Var, Expr *Cond, Stmt *Then,
+               SourceLocation EL, Stmt *Else)
+    : Stmt(IfStmtClass) {
+  bool HasElse = !!Else;
+  bool HasVar = !!Var;
+  bool HasInit = !!Init;
+  IfStmtBits.HasElse = HasElse;
+  IfStmtBits.HasVar = HasVar;
+  IfStmtBits.HasInit = HasInit;
+
   setConstexpr(IsConstexpr);
-  setConditionVariable(C, var);
-  SubExprs[INIT] = init;
-  SubExprs[COND] = cond;
-  SubExprs[THEN] = then;
-  SubExprs[ELSE] = elsev;
-}
 
-VarDecl *IfStmt::getConditionVariable() const {
-  if (!SubExprs[VAR])
+  setCond(Cond);
+  setThen(Then);
+  if (HasElse)
+    setElse(Else);
+  if (HasVar)
+    setConditionVariable(C, Var);
+  if (HasInit)
+    setInit(Init);
+
+  setIfLoc(IL);
+  if (HasElse)
+    setElseLoc(EL);
+}
+
+IfStmt::IfStmt(EmptyShell Empty, bool HasElse, bool HasVar, bool HasInit)
+    : Stmt(IfStmtClass, Empty) {
+  IfStmtBits.HasElse = HasElse;
+  IfStmtBits.HasVar = HasVar;
+  IfStmtBits.HasInit = HasInit;
+}
+
+IfStmt *IfStmt::Create(const ASTContext &Ctx, SourceLocation IL,
+                       bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond,
+                       Stmt *Then, SourceLocation EL, Stmt *Else) {
+  bool HasElse = !!Else;
+  bool HasVar = !!Var;
+  bool HasInit = !!Init;
+  void *Mem = Ctx.Allocate(
+      totalSizeToAlloc<Stmt *, SourceLocation>(
+          NumMandatoryStmtPtr + HasElse + HasVar + HasInit, HasElse),
+      alignof(IfStmt));
+  return new (Mem)
+      IfStmt(Ctx, IL, IsConstexpr, Init, Var, Cond, Then, EL, Else);
+}
+
+IfStmt *IfStmt::CreateEmpty(const ASTContext &Ctx, bool HasElse, bool HasVar,
+                            bool HasInit) {
+  void *Mem = Ctx.Allocate(
+      totalSizeToAlloc<Stmt *, SourceLocation>(
+          NumMandatoryStmtPtr + HasElse + HasVar + HasInit, HasElse),
+      alignof(IfStmt));
+  return new (Mem) IfStmt(EmptyShell(), HasElse, HasVar, HasInit);
+}
+
+VarDecl *IfStmt::getConditionVariable() {
+  auto *DS = getConditionVariableDeclStmt();
+  if (!DS)
     return nullptr;
-
-  auto *DS = cast<DeclStmt>(SubExprs[VAR]);
   return cast<VarDecl>(DS->getSingleDecl());
 }
 
-void IfStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
+void IfStmt::setConditionVariable(const ASTContext &Ctx, VarDecl *V) {
+  assert(hasVar() &&
+         "This if statement has no storage for a condition variable!");
+
   if (!V) {
-    SubExprs[VAR] = nullptr;
+    getTrailingObjects<Stmt *>()[getVarOffset()] = nullptr;
     return;
   }
 
   SourceRange VarRange = V->getSourceRange();
-  SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(),
-                                   VarRange.getEnd());
+  getTrailingObjects<Stmt *>()[getVarOffset()] = new (Ctx)
+      DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd());
 }
 
 bool IfStmt::isObjCAvailabilityCheck() const {
-  return isa<ObjCAvailabilityCheckExpr>(SubExprs[COND]);
+  return isa<ObjCAvailabilityCheckExpr>(getCond());
 }
 
 ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -5772,10 +5772,9 @@
       ToIfLoc, ToInit, ToConditionVariable, ToCond, ToThen, ToElseLoc, ToElse) =
           *Imp;
 
-  return new (Importer.getToContext()) IfStmt(
-      Importer.getToContext(),
-      ToIfLoc, S->isConstexpr(), ToInit, ToConditionVariable, ToCond,
-      ToThen, ToElseLoc, ToElse);
+  return IfStmt::Create(Importer.getToContext(), ToIfLoc, S->isConstexpr(),
+                        ToInit, ToConditionVariable, ToCond, ToThen, ToElseLoc,
+                        ToElse);
 }
 
 ExpectedStmt ASTNodeImporter::VisitSwitchStmt(SwitchStmt *S) {
Index: include/clang/AST/Stmt.h
===================================================================
--- include/clang/AST/Stmt.h
+++ include/clang/AST/Stmt.h
@@ -151,11 +151,25 @@
   };
 
   class IfStmtBitfields {
+    friend class ASTStmtReader;
     friend class IfStmt;
 
     unsigned : NumStmtBits;
 
+    /// True if this if statement is a constexpr if.
     unsigned IsConstexpr : 1;
+
+    /// True if this if statement has storage for an else statement.
+    unsigned HasElse : 1;
+
+    /// True if this if statement has storage for a variable declaration.
+    unsigned HasVar : 1;
+
+    /// True if this if statement has storage for an init statement.
+    unsigned HasInit : 1;
+
+    /// The location of the "if".
+    SourceLocation IfLoc;
   };
 
   class SwitchStmtBitfields {
@@ -1100,21 +1114,110 @@
 };
 
 /// IfStmt - This represents an if/then/else.
-class IfStmt : public Stmt {
-  enum { INIT, VAR, COND, THEN, ELSE, END_EXPR };
-  Stmt* SubExprs[END_EXPR];
+class IfStmt final
+    : public Stmt,
+      private llvm::TrailingObjects<IfStmt, Stmt *, SourceLocation> {
+  friend TrailingObjects;
 
-  SourceLocation IfLoc;
-  SourceLocation ElseLoc;
+  // IfStmt is followed by several trailing objects, some of which optional.
+  // They are in order:
+  //
+  // * A "Stmt *" for the condition.
+  //    Always present. This is in fact a "Expr *".
+  //
+  // * A "Stmt *" for the then statement.
+  //    Always present.
+  //
+  // * A "Stmt *" for the else statement.
+  //    Present if and only if hasElse().
+  //
+  // * A "Stmt *" for the condition variable.
+  //    Present if and only if hasVar(). This is in fact a "DeclStmt *".
+  //
+  // * A "Stmt *" for the init statement.
+  //    Present if and only if hasInit().
+  //
+  // * A "SourceLocation" for the location of the "else".
+  //    Present if and only if hasElse().
+  //
+  // For the common case of an if statement of the form
+  //
+  //  if (some_condition)
+  //    some_statement
+  //
+  // the only trailing objects will be the first two "Stmt *" for the
+  // condition and the then statement.
+  enum { COND, THEN, ELSE };
+  enum { NumMandatoryStmtPtr = 2 };
+
+  unsigned numTrailingObjects(OverloadToken<Stmt *>) const {
+    return NumMandatoryStmtPtr + hasElse() + hasVar() + hasInit();
+  }
+
+  unsigned numTrailingObjects(OverloadToken<SourceLocation>) const {
+    return hasElse();
+  }
+
+  /// True if this IfStmt has storage for an else statement.
+  bool hasElse() const { return IfStmtBits.HasElse; }
+
+  /// True if this IfStmt has storage for a variable declaration.
+  bool hasVar() const { return IfStmtBits.HasVar; }
+
+  /// True if this IfStmt has the storage for an init statement.
+  bool hasInit() const { return IfStmtBits.HasInit; }
+
+  unsigned getVarOffset() const { return ELSE + hasElse(); }
+  unsigned getInitOffset() const { return ELSE + hasElse() + hasVar(); }
+
+  /// Build an if/then/else statement.
+  IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, Stmt *Init,
+         VarDecl *Var, Expr *Cond, Stmt *Then, SourceLocation EL, Stmt *Else);
+
+  /// Build an empty if/then/else statement.
+  explicit IfStmt(EmptyShell Empty, bool HasElse, bool HasVar, bool HasInit);
 
 public:
-  IfStmt(const ASTContext &C, SourceLocation IL,
-         bool IsConstexpr, Stmt *init, VarDecl *var, Expr *cond,
-         Stmt *then, SourceLocation EL = SourceLocation(),
-         Stmt *elsev = nullptr);
+  /// Create an IfStmt.
+  static IfStmt *Create(const ASTContext &Ctx, SourceLocation IL,
+                        bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond,
+                        Stmt *Then, SourceLocation EL = SourceLocation(),
+                        Stmt *Else = nullptr);
+
+  /// Create an empty IfStmt optionally with storage for an else statement,
+  /// condition variable and init expression.
+  static IfStmt *CreateEmpty(const ASTContext &Ctx, bool HasElse, bool HasVar,
+                             bool HasInit);
 
-  /// Build an empty if/then/else statement
-  explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) {}
+  Expr *getCond() {
+    return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[COND]);
+  }
+
+  const Expr *getCond() const {
+    return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[COND]);
+  }
+
+  void setCond(Expr *Cond) {
+    getTrailingObjects<Stmt *>()[COND] = reinterpret_cast<Stmt *>(Cond);
+  }
+
+  Stmt *getThen() { return getTrailingObjects<Stmt *>()[THEN]; }
+  const Stmt *getThen() const { return getTrailingObjects<Stmt *>()[THEN]; }
+  void setThen(Stmt *Then) { getTrailingObjects<Stmt *>()[THEN] = Then; }
+
+  Stmt *getElse() {
+    return hasElse() ? getTrailingObjects<Stmt *>()[ELSE] : nullptr;
+  }
+
+  const Stmt *getElse() const {
+    return hasElse() ? getTrailingObjects<Stmt *>()[ELSE] : nullptr;
+  }
+
+  void setElse(Stmt *Else) {
+    assert(hasElse() &&
+           "This if statement has no storage for an else statement!");
+    getTrailingObjects<Stmt *>()[ELSE] = Else;
+  }
 
   /// Retrieve the variable declared in this "if" statement, if any.
   ///
@@ -1124,52 +1227,74 @@
   ///   printf("x is %d", x);
   /// }
   /// \endcode
-  VarDecl *getConditionVariable() const;
-  void setConditionVariable(const ASTContext &C, VarDecl *V);
+  VarDecl *getConditionVariable();
+  const VarDecl *getConditionVariable() const {
+    return const_cast<IfStmt *>(this)->getConditionVariable();
+  }
+
+  /// Set the condition variable for this if statement.
+  /// The if statement must have storage for the condition variable.
+  void setConditionVariable(const ASTContext &Ctx, VarDecl *V);
 
   /// If this IfStmt has a condition variable, return the faux DeclStmt
   /// associated with the creation of that condition variable.
+  DeclStmt *getConditionVariableDeclStmt() {
+    return hasVar() ? static_cast<DeclStmt *>(
+                          getTrailingObjects<Stmt *>()[getVarOffset()])
+                    : nullptr;
+  }
+
   const DeclStmt *getConditionVariableDeclStmt() const {
-    return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
+    return hasVar() ? static_cast<DeclStmt *>(
+                          getTrailingObjects<Stmt *>()[getVarOffset()])
+                    : nullptr;
   }
 
-  Stmt *getInit() { return SubExprs[INIT]; }
-  const Stmt *getInit() const { return SubExprs[INIT]; }
-  void setInit(Stmt *S) { SubExprs[INIT] = S; }
-  const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);}
-  void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); }
-  const Stmt *getThen() const { return SubExprs[THEN]; }
-  void setThen(Stmt *S) { SubExprs[THEN] = S; }
-  const Stmt *getElse() const { return SubExprs[ELSE]; }
-  void setElse(Stmt *S) { SubExprs[ELSE] = S; }
+  Stmt *getInit() {
+    return hasInit() ? getTrailingObjects<Stmt *>()[getInitOffset()] : nullptr;
+  }
 
-  Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
-  Stmt *getThen() { return SubExprs[THEN]; }
-  Stmt *getElse() { return SubExprs[ELSE]; }
+  const Stmt *getInit() const {
+    return hasInit() ? getTrailingObjects<Stmt *>()[getInitOffset()] : nullptr;
+  }
 
-  SourceLocation getIfLoc() const { return IfLoc; }
-  void setIfLoc(SourceLocation L) { IfLoc = L; }
-  SourceLocation getElseLoc() const { return ElseLoc; }
-  void setElseLoc(SourceLocation L) { ElseLoc = L; }
+  void setInit(Stmt *Init) {
+    assert(hasInit() &&
+           "This if statement has no storage for an init statement!");
+    getTrailingObjects<Stmt *>()[getInitOffset()] = Init;
+  }
+
+  SourceLocation getIfLoc() const { return IfStmtBits.IfLoc; }
+  void setIfLoc(SourceLocation IfLoc) { IfStmtBits.IfLoc = IfLoc; }
+
+  SourceLocation getElseLoc() const {
+    return hasElse() ? *getTrailingObjects<SourceLocation>() : SourceLocation();
+  }
+
+  void setElseLoc(SourceLocation ElseLoc) {
+    assert(hasElse() &&
+           "This if statement has no storage for an else statement!");
+    *getTrailingObjects<SourceLocation>() = ElseLoc;
+  }
 
   bool isConstexpr() const { return IfStmtBits.IsConstexpr; }
   void setConstexpr(bool C) { IfStmtBits.IsConstexpr = C; }
 
   bool isObjCAvailabilityCheck() const;
 
-  SourceLocation getBeginLoc() const LLVM_READONLY { return IfLoc; }
-
+  SourceLocation getBeginLoc() const { return getIfLoc(); }
   SourceLocation getEndLoc() const LLVM_READONLY {
-    if (SubExprs[ELSE])
-      return SubExprs[ELSE]->getEndLoc();
-    else
-      return SubExprs[THEN]->getEndLoc();
+    if (hasElse())
+      return getElse()->getEndLoc();
+    return getThen()->getEndLoc();
   }
 
   // Iterators over subexpressions.  The iterators will include iterating
   // over the initialization expression referenced by the condition variable.
   child_range children() {
-    return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR);
+    return child_range(getTrailingObjects<Stmt *>(),
+                       getTrailingObjects<Stmt *>() +
+                           numTrailingObjects(OverloadToken<Stmt *>()));
   }
 
   static bool classof(const Stmt *T) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to