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 { + 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) const { + return NumMandatoryStmtPtr + hasElseStorage() + hasVarStorage() + + hasInitStorage(); + } + + unsigned numTrailingObjects(OverloadToken) 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(getTrailingObjects()[condOffset()]); + } + + const Expr *getCond() const { + return reinterpret_cast(getTrailingObjects()[condOffset()]); + } - /// Build an empty if/then/else statement - explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) {} + void setCond(Expr *Cond) { + getTrailingObjects()[condOffset()] = reinterpret_cast(Cond); + } + + Stmt *getThen() { return getTrailingObjects()[thenOffset()]; } + const Stmt *getThen() const { + return getTrailingObjects()[thenOffset()]; + } + + void setThen(Stmt *Then) { + getTrailingObjects()[thenOffset()] = Then; + } + + Stmt *getElse() { + return hasElseStorage() ? getTrailingObjects()[elseOffset()] + : nullptr; + } + + const Stmt *getElse() const { + return hasElseStorage() ? getTrailingObjects()[elseOffset()] + : nullptr; + } + + void setElse(Stmt *Else) { + assert(hasElseStorage() && + "This if statement has no storage for an else statement!"); + getTrailingObjects()[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(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( + getTrailingObjects()[varOffset()]) + : nullptr; + } + const DeclStmt *getConditionVariableDeclStmt() const { - return reinterpret_cast(SubExprs[VAR]); + return hasVarStorage() ? static_cast( + getTrailingObjects()[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(SubExprs[COND]);} - void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast(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()[initOffset()] + : nullptr; + } - Expr *getCond() { return reinterpret_cast(SubExprs[COND]); } - Stmt *getThen() { return SubExprs[THEN]; } - Stmt *getElse() { return SubExprs[ELSE]; } + const Stmt *getInit() const { + return hasInitStorage() ? getTrailingObjects()[initOffset()] + : nullptr; + } + + void setInit(Stmt *Init) { + assert(hasInitStorage() && + "This if statement has no storage for an init statement!"); + getTrailingObjects()[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(); + } + + void setElseLoc(SourceLocation ElseLoc) { + assert(hasElseStorage() && + "This if statement has no storage for an else statement!"); + *getTrailingObjects() = 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(), + getTrailingObjects() + + numTrailingObjects(OverloadToken())); } static bool classof(const Stmt *T) { 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: 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/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( + 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( + 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(SubExprs[VAR]); return cast(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()[varOffset()] = nullptr; return; } SourceRange VarRange = V->getSourceRange(); - SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(), - VarRange.getEnd()); + getTrailingObjects()[varOffset()] = new (Ctx) + DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd()); } bool IfStmt::isObjCAvailabilityCheck() const { - return isa(SubExprs[COND]); + return isa(getCond()); } ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, 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/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/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()); + 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()); + 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/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: test/Import/if-stmt/test.cpp =================================================================== --- test/Import/if-stmt/test.cpp +++ test/Import/if-stmt/test.cpp @@ -1,14 +1,10 @@ // RUN: clang-import-test -dump-ast -import %S/Inputs/F.cpp -expression %s | FileCheck %s // CHECK: IfStmt -// CHECK-NEXT: <> -// CHECK-NEXT: <> // CHECK-NEXT: CXXBoolLiteralExpr // CHECK-NEXT: ReturnStmt -// CHECK-NEXT: <> // CHECK: IfStmt -// CHECK-NEXT: <> // CHECK-NEXT: DeclStmt // CHECK-NEXT: VarDecl // CHECK-NEXT: IntegerLiteral @@ -16,26 +12,19 @@ // CHECK-NEXT: ImplicitCastExpr // CHECK-NEXT: DeclRefExpr // CHECK-NEXT: ReturnStmt -// CHECK-NEXT: <> // CHECK: IfStmt // CHECK-NEXT: DeclStmt // CHECK-NEXT: VarDecl -// CHECK-NEXT: <> // CHECK-NEXT: CXXBoolLiteralExpr // CHECK-NEXT: ReturnStmt -// CHECK-NEXT: <> // CHECK: IfStmt -// CHECK-NEXT: <> -// CHECK-NEXT: <> // CHECK-NEXT: CXXBoolLiteralExpr // CHECK-NEXT: ReturnStmt // CHECK-NEXT: ReturnStmt // CHECK: IfStmt -// CHECK-NEXT: <> -// CHECK-NEXT: <> // CHECK-NEXT: CXXBoolLiteralExpr // CHECK-NEXT: CompoundStmt // CHECK-NEXT: ReturnStmt 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 {{.*}} -// CHECK-NEXT: |-<<>> -// CHECK-NEXT: |-<<>> // CHECK-NEXT: |-OpaqueValueExpr {{.*}} <> 'bool' // CHECK-NEXT: |-ReturnStmt {{.*}} // CHECK-NEXT: | `-IntegerLiteral {{.*}} 'int' 4 @@ -50,15 +48,15 @@ { return 45; } } // CHECK: NamespaceDecl {{.*}} <{{.*}}> {{.*}} TestInvalidFunctionDecl -// CHECK-NEXT: |-CXXRecordDecl {{.*}} line:46:8 struct Str definition +// CHECK-NEXT: |-CXXRecordDecl {{.*}} line:44:8 struct Str definition // CHECK: | |-CXXRecordDecl {{.*}} col:8 implicit struct Str -// CHECK-NEXT: | `-CXXMethodDecl {{.*}} col:11 invalid foo1 'double (double, int)' +// CHECK-NEXT: | `-CXXMethodDecl {{.*}} col:11 invalid foo1 'double (double, int)' // CHECK-NEXT: | |-ParmVarDecl {{.*}} col:22 'double' // CHECK-NEXT: | `-ParmVarDecl {{.*}} > col:36 invalid 'int' -// CHECK-NEXT: `-CXXMethodDecl {{.*}} parent {{.*}} line:49:13 invalid foo1 'double (double, int)' +// CHECK-NEXT: `-CXXMethodDecl {{.*}} parent {{.*}} line:47:13 invalid foo1 'double (double, int)' // CHECK-NEXT: |-ParmVarDecl {{.*}} col:24 'double' // CHECK-NEXT: |-ParmVarDecl {{.*}} > col:38 invalid 'int' -// CHECK-NEXT: `-CompoundStmt {{.*}} +// CHECK-NEXT: `-CompoundStmt {{.*}} // CHECK-NEXT: `-ReturnStmt {{.*}} // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'double' // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 45