riccibruno updated this revision to Diff 171332.
riccibruno added a reviewer: rsmith.
riccibruno added a comment.

Add a flag to the output of -ast-dump indicating
which sub-statement `IfStmt` is storing. This removes
the ambiguity in the output of -ast-dump and addresses
rsmith's comment in https://reviews.llvm.org/D53717.


Repository:
  rC Clang

https://reviews.llvm.org/D53607

Files:
  include/clang/AST/Stmt.h
  lib/AST/ASTDumper.cpp
  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: CXXBoolLiteralExpr
 // CHECK-NEXT: ReturnStmt
-// CHECK-NEXT: <<NULL>>
 
 // 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() != nullptr;
+  bool HasVar = S->getConditionVariableDeclStmt() != nullptr;
+  bool HasInit = S->getInit() != nullptr;
+
   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
@@ -799,39 +799,86 @@
                  });
 }
 
-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) {
+IfStmt::IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr,
+               Stmt *Init, VarDecl *Var, Expr *Cond, Stmt *Then,
+               SourceLocation EL, Stmt *Else)
+    : Stmt(IfStmtClass) {
+  bool HasElse = Else != nullptr;
+  bool HasVar = Var != nullptr;
+  bool HasInit = Init != nullptr;
+  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(Ctx, 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 != nullptr;
+  bool HasVar = Var != nullptr;
+  bool HasInit = Init != nullptr;
+  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(hasVarStorage() &&
+         "This if statement has no storage for a condition variable!");
+
   if (!V) {
-    SubExprs[VAR] = nullptr;
+    getTrailingObjects<Stmt *>()[varOffset()] = nullptr;
     return;
   }
 
   SourceRange VarRange = V->getSourceRange();
-  SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(),
-                                   VarRange.getEnd());
+  getTrailingObjects<Stmt *>()[varOffset()] = 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: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -511,6 +511,7 @@
     void VisitStmt(const Stmt *Node);
     void VisitDeclStmt(const DeclStmt *Node);
     void VisitAttributedStmt(const AttributedStmt *Node);
+    void VisitIfStmt(const IfStmt *Node);
     void VisitLabelStmt(const LabelStmt *Node);
     void VisitGotoStmt(const GotoStmt *Node);
     void VisitCXXCatchStmt(const CXXCatchStmt *Node);
@@ -2020,6 +2021,16 @@
     dumpAttr(*I);
 }
 
+void ASTDumper::VisitIfStmt(const IfStmt *Node) {
+  VisitStmt(Node);
+  if (Node->hasInitStorage())
+    OS << " has_init";
+  if (Node->hasVarStorage())
+    OS << " has_var";
+  if (Node->hasElseStorage())
+    OS << " has_else";
+}
+
 void ASTDumper::VisitLabelStmt(const LabelStmt *Node) {
   VisitStmt(Node);
   OS << " '" << Node->getName() << "'";
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,117 @@
 };
 
 /// 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.
+  // Note that it would be more convenient to put the optional trailing
+  // objects at then end but this would change the order of the children.
+  // The trailing objects are in order:
+  //
+  // * A "Stmt *" for the init statement.
+  //    Present if and only if hasInitStorage().
+  //
+  // * A "Stmt *" for the condition variable.
+  //    Present if and only if hasVarStorage(). This is in fact a "DeclStmt *".
+  //
+  // * 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 hasElseStorage().
+  //
+  // * A "SourceLocation" for the location of the "else".
+  //    Present if and only if hasElseStorage().
+  enum { InitOffset = 0, ThenOffsetFromCond = 1, ElseOffsetFromCond = 2 };
+  enum { NumMandatoryStmtPtr = 2 };
+
+  unsigned numTrailingObjects(OverloadToken<Stmt *>) const {
+    return NumMandatoryStmtPtr + hasElseStorage() + hasVarStorage() +
+           hasInitStorage();
+  }
+
+  unsigned numTrailingObjects(OverloadToken<SourceLocation>) const {
+    return hasElseStorage();
+  }
+
+  unsigned initOffset() const { return InitOffset; }
+  unsigned varOffset() const { return InitOffset + hasInitStorage(); }
+  unsigned condOffset() const {
+    return InitOffset + hasInitStorage() + hasVarStorage();
+  }
+  unsigned thenOffset() const { return condOffset() + ThenOffsetFromCond; }
+  unsigned elseOffset() const { return condOffset() + ElseOffsetFromCond; }
+
+  /// 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);
+
+  /// True if this IfStmt has the storage for an init statement.
+  bool hasInitStorage() const { return IfStmtBits.HasInit; }
+
+  /// True if this IfStmt has storage for a variable declaration.
+  bool hasVarStorage() const { return IfStmtBits.HasVar; }
+
+  /// True if this IfStmt has storage for an else statement.
+  bool hasElseStorage() const { return IfStmtBits.HasElse; }
+
+  Expr *getCond() {
+    return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]);
+  }
+
+  const Expr *getCond() const {
+    return reinterpret_cast<Expr *>(getTrailingObjects<Stmt *>()[condOffset()]);
+  }
 
-  /// Build an empty if/then/else statement
-  explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) {}
+  void setCond(Expr *Cond) {
+    getTrailingObjects<Stmt *>()[condOffset()] = reinterpret_cast<Stmt *>(Cond);
+  }
+
+  Stmt *getThen() { return getTrailingObjects<Stmt *>()[thenOffset()]; }
+  const Stmt *getThen() const {
+    return getTrailingObjects<Stmt *>()[thenOffset()];
+  }
+
+  void setThen(Stmt *Then) {
+    getTrailingObjects<Stmt *>()[thenOffset()] = Then;
+  }
+
+  Stmt *getElse() {
+    return hasElseStorage() ? getTrailingObjects<Stmt *>()[elseOffset()]
+                            : nullptr;
+  }
+
+  const Stmt *getElse() const {
+    return hasElseStorage() ? getTrailingObjects<Stmt *>()[elseOffset()]
+                            : nullptr;
+  }
+
+  void setElse(Stmt *Else) {
+    assert(hasElseStorage() &&
+           "This if statement has no storage for an else statement!");
+    getTrailingObjects<Stmt *>()[elseOffset()] = Else;
+  }
 
   /// Retrieve the variable declared in this "if" statement, if any.
   ///
@@ -1124,52 +1234,77 @@
   ///   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 hasVarStorage() ? static_cast<DeclStmt *>(
+                                 getTrailingObjects<Stmt *>()[varOffset()])
+                           : nullptr;
+  }
+
   const DeclStmt *getConditionVariableDeclStmt() const {
-    return reinterpret_cast<DeclStmt*>(SubExprs[VAR]);
+    return hasVarStorage() ? static_cast<DeclStmt *>(
+                                 getTrailingObjects<Stmt *>()[varOffset()])
+                           : 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 hasInitStorage() ? getTrailingObjects<Stmt *>()[initOffset()]
+                            : nullptr;
+  }
 
-  Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
-  Stmt *getThen() { return SubExprs[THEN]; }
-  Stmt *getElse() { return SubExprs[ELSE]; }
+  const Stmt *getInit() const {
+    return hasInitStorage() ? getTrailingObjects<Stmt *>()[initOffset()]
+                            : nullptr;
+  }
+
+  void setInit(Stmt *Init) {
+    assert(hasInitStorage() &&
+           "This if statement has no storage for an init statement!");
+    getTrailingObjects<Stmt *>()[initOffset()] = Init;
+  }
 
-  SourceLocation getIfLoc() const { return IfLoc; }
-  void setIfLoc(SourceLocation L) { IfLoc = L; }
-  SourceLocation getElseLoc() const { return ElseLoc; }
-  void setElseLoc(SourceLocation L) { ElseLoc = L; }
+  SourceLocation getIfLoc() const { return IfStmtBits.IfLoc; }
+  void setIfLoc(SourceLocation IfLoc) { IfStmtBits.IfLoc = IfLoc; }
+
+  SourceLocation getElseLoc() const {
+    return hasElseStorage() ? *getTrailingObjects<SourceLocation>()
+                            : SourceLocation();
+  }
+
+  void setElseLoc(SourceLocation ElseLoc) {
+    assert(hasElseStorage() &&
+           "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 (getElse())
+      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