Author: brunoricci Date: Sat Oct 27 14:12:20 2018 New Revision: 345464 URL: http://llvm.org/viewvc/llvm-project?rev=345464&view=rev Log: [AST] Only store the needed data in IfStmt
Only store the needed data in IfStmt. This cuts the size of IfStmt by up to 3 pointers + 1 SourceLocation. The order of the children is intentionally kept the same even though it would be more convenient to put the optional trailing objects last. Additionally use the newly available space in the bit-fields of Stmt to store the location of the "if". The result of this is that for the common case of an if statement of the form: if (some_cond) some_statement the size of IfStmt is brought down to 8 bytes + 2 pointers, instead of 8 bytes + 5 pointers + 2 SourceLocation. Differential Revision: https://reviews.llvm.org/D53607 Reviewed By: rjmccall Modified: cfe/trunk/include/clang/AST/Stmt.h cfe/trunk/lib/AST/ASTDumper.cpp cfe/trunk/lib/AST/ASTImporter.cpp cfe/trunk/lib/AST/Stmt.cpp cfe/trunk/lib/Analysis/BodyFarm.cpp cfe/trunk/lib/Sema/SemaStmt.cpp cfe/trunk/lib/Serialization/ASTReaderStmt.cpp cfe/trunk/lib/Serialization/ASTWriterStmt.cpp cfe/trunk/test/Import/if-stmt/test.cpp cfe/trunk/test/Misc/ast-dump-invalid.cpp Modified: cfe/trunk/include/clang/AST/Stmt.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=345464&r1=345463&r2=345464&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Stmt.h (original) +++ cfe/trunk/include/clang/AST/Stmt.h Sat Oct 27 14:12:20 2018 @@ -151,11 +151,25 @@ protected: }; 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 @@ public: }; /// 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; + + // 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); - SourceLocation IfLoc; - SourceLocation ElseLoc; + /// 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()]); + } + + 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; + } - /// Build an empty if/then/else statement - explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) {} + 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 @@ public: /// 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; } - - Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } - Stmt *getThen() { return SubExprs[THEN]; } - Stmt *getElse() { return SubExprs[ELSE]; } - - SourceLocation getIfLoc() const { return IfLoc; } - void setIfLoc(SourceLocation L) { IfLoc = L; } - SourceLocation getElseLoc() const { return ElseLoc; } - void setElseLoc(SourceLocation L) { ElseLoc = L; } + Stmt *getInit() { + return hasInitStorage() ? getTrailingObjects<Stmt *>()[initOffset()] + : nullptr; + } + + 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 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) { Modified: cfe/trunk/lib/AST/ASTDumper.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=345464&r1=345463&r2=345464&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTDumper.cpp (original) +++ cfe/trunk/lib/AST/ASTDumper.cpp Sat Oct 27 14:12:20 2018 @@ -511,6 +511,7 @@ namespace { 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 @@ void ASTDumper::VisitAttributedStmt(cons 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() << "'"; Modified: cfe/trunk/lib/AST/ASTImporter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=345464&r1=345463&r2=345464&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTImporter.cpp (original) +++ cfe/trunk/lib/AST/ASTImporter.cpp Sat Oct 27 14:12:20 2018 @@ -5772,10 +5772,9 @@ ExpectedStmt ASTNodeImporter::VisitIfStm 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) { Modified: cfe/trunk/lib/AST/Stmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Stmt.cpp?rev=345464&r1=345463&r2=345464&view=diff ============================================================================== --- cfe/trunk/lib/AST/Stmt.cpp (original) +++ cfe/trunk/lib/AST/Stmt.cpp Sat Oct 27 14:12:20 2018 @@ -799,39 +799,86 @@ void MSAsmStmt::initialize(const ASTCont }); } -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; + + setCond(Cond); + setThen(Then); + if (HasElse) + setElse(Else); + if (HasVar) + setConditionVariable(Ctx, Var); + if (HasInit) + setInit(Init); + + setIfLoc(IL); + if (HasElse) + setElseLoc(EL); } -VarDecl *IfStmt::getConditionVariable() const { - if (!SubExprs[VAR]) - return nullptr; +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); +} - auto *DS = cast<DeclStmt>(SubExprs[VAR]); +VarDecl *IfStmt::getConditionVariable() { + auto *DS = getConditionVariableDeclStmt(); + if (!DS) + return nullptr; 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, Modified: cfe/trunk/lib/Analysis/BodyFarm.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/BodyFarm.cpp?rev=345464&r1=345463&r2=345464&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/BodyFarm.cpp (original) +++ cfe/trunk/lib/Analysis/BodyFarm.cpp Sat Oct 27 14:12:20 2018 @@ -464,13 +464,13 @@ static Stmt *create_call_once(ASTContext 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 @@ static Stmt *create_dispatch_once(ASTCon 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 @@ static Stmt *create_OSAtomicCompareAndSw 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; } Modified: cfe/trunk/lib/Sema/SemaStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=345464&r1=345463&r2=345464&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaStmt.cpp (original) +++ cfe/trunk/lib/Sema/SemaStmt.cpp Sat Oct 27 14:12:20 2018 @@ -577,9 +577,8 @@ StmtResult Sema::BuildIfStmt(SourceLocat 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 { Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=345464&r1=345463&r2=345464&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Sat Oct 27 14:12:20 2018 @@ -215,14 +215,24 @@ void ASTStmtReader::VisitAttributedStmt( 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 @@ Stmt *ASTReader::ReadStmtFromStream(Modu 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: Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=345464&r1=345463&r2=345464&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Sat Oct 27 14:12:20 2018 @@ -128,14 +128,29 @@ void ASTStmtWriter::VisitAttributedStmt( 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; } Modified: cfe/trunk/test/Import/if-stmt/test.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Import/if-stmt/test.cpp?rev=345464&r1=345463&r2=345464&view=diff ============================================================================== --- cfe/trunk/test/Import/if-stmt/test.cpp (original) +++ cfe/trunk/test/Import/if-stmt/test.cpp Sat Oct 27 14:12:20 2018 @@ -1,14 +1,10 @@ // 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 @@ -16,26 +12,19 @@ // 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 Modified: cfe/trunk/test/Misc/ast-dump-invalid.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/ast-dump-invalid.cpp?rev=345464&r1=345463&r2=345464&view=diff ============================================================================== --- cfe/trunk/test/Misc/ast-dump-invalid.cpp (original) +++ cfe/trunk/test/Misc/ast-dump-invalid.cpp Sat Oct 27 14:12:20 2018 @@ -33,8 +33,6 @@ int g(int i) { // 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 @@ double Str::foo1(double, invalid_type) { 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits