ForStatement(ASTScope *sc, Statement *d, Expression *c, Statement *u, Statement *b, ElseStatement *e, SourceLocation l = SourceLocation()) : LoopStatement(sc, c, u, b, e, l), decl(d) {}
/** * @return this, because we never interpret it. * @param environment Not used. */ Element Quoted_::Interpret_(Environment& /* environment */) { return Quoted(shared_from_this(), SourceLocation()); }
void HandleTagDeclDefinition(TagDecl *D) override { PrettyStackTraceDecl CrashInfo(D, SourceLocation(), Context->getSourceManager(), "LLVM IR generation of declaration"); Gen->HandleTagDeclDefinition(D); }
/// \brief Given a location that specifies the start of a /// token, return a new location that specifies a character within the token. SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart, unsigned Char) const { return SourceLocation(); }
/// CheckExceptionSpecSubset - Check whether the second function type's /// exception specification is a subset (or equivalent) of the first function /// type. This is used by override and pointer assignment checks. bool Sema::CheckExceptionSpecSubset( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Superset, SourceLocation SuperLoc, const FunctionProtoType *Subset, SourceLocation SubLoc) { // Just auto-succeed under -fno-exceptions. if (!getLangOptions().Exceptions) return false; // FIXME: As usual, we could be more specific in our error messages, but // that better waits until we've got types with source locations. if (!SubLoc.isValid()) SubLoc = SuperLoc; // If superset contains everything, we're done. if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec()) return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); // It does not. If the subset contains everything, we've failed. if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) { Diag(SubLoc, DiagID); if (NoteID.getDiagID() != 0) Diag(SuperLoc, NoteID); return true; } // Neither contains everything. Do a proper comparison. for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(), SubE = Subset->exception_end(); SubI != SubE; ++SubI) { // Take one type from the subset. QualType CanonicalSubT = Context.getCanonicalType(*SubI); // Unwrap pointers and references so that we can do checks within a class // hierarchy. Don't unwrap member pointers; they don't have hierarchy // conversions on the pointee. bool SubIsPointer = false; if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>()) CanonicalSubT = RefTy->getPointeeType(); if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) { CanonicalSubT = PtrTy->getPointeeType(); SubIsPointer = true; } bool SubIsClass = CanonicalSubT->isRecordType(); CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType(); CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/false); bool Contained = false; // Make sure it's in the superset. for (FunctionProtoType::exception_iterator SuperI = Superset->exception_begin(), SuperE = Superset->exception_end(); SuperI != SuperE; ++SuperI) { QualType CanonicalSuperT = Context.getCanonicalType(*SuperI); // SubT must be SuperT or derived from it, or pointer or reference to // such types. if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>()) CanonicalSuperT = RefTy->getPointeeType(); if (SubIsPointer) { if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>()) CanonicalSuperT = PtrTy->getPointeeType(); else { continue; } } CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType(); // If the types are the same, move on to the next type in the subset. if (CanonicalSubT == CanonicalSuperT) { Contained = true; break; } // Otherwise we need to check the inheritance. if (!SubIsClass || !CanonicalSuperT->isRecordType()) continue; Paths.clear(); if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths)) continue; if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT))) continue; // Do this check from a context without privileges. switch (CheckBaseClassAccess(SourceLocation(), CanonicalSuperT, CanonicalSubT, Paths.front(), /*Diagnostic*/ 0, /*ForceCheck*/ true, /*ForceUnprivileged*/ true)) { case AR_accessible: break; case AR_inaccessible: continue; case AR_dependent: llvm_unreachable("access check dependent for unprivileged context"); break; case AR_delayed: llvm_unreachable("access check delayed in non-declaration"); break; } Contained = true; break; } if (!Contained) { Diag(SubLoc, DiagID); if (NoteID.getDiagID() != 0) Diag(SuperLoc, NoteID); return true; } } // We've run half the gauntlet. return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); }
/** * Interpret. Should just return this. */ Element Error_::Interpret_(Environment&) { return Error(shared_from_this(), SourceLocation()); }
bool DeclExtractor::ExtractDecl(Decl* D) { FunctionDecl* FD = dyn_cast<FunctionDecl>(D); if (FD) { if (FD->getNameAsString().find("__cling_Un1Qu3")) return true; llvm::SmallVector<NamedDecl*, 4> TouchedDecls; CompoundStmt* CS = dyn_cast<CompoundStmt>(FD->getBody()); assert(CS && "Function body not a CompoundStmt?"); DeclContext* DC = FD->getTranslationUnitDecl(); Scope* TUScope = m_Sema->TUScope; assert(TUScope == m_Sema->getScopeForContext(DC) && "TU scope from DC?"); llvm::SmallVector<Stmt*, 4> Stmts; for (CompoundStmt::body_iterator I = CS->body_begin(), EI = CS->body_end(); I != EI; ++I) { DeclStmt* DS = dyn_cast<DeclStmt>(*I); if (!DS) { Stmts.push_back(*I); continue; } for (DeclStmt::decl_iterator J = DS->decl_begin(); J != DS->decl_end(); ++J) { NamedDecl* ND = dyn_cast<NamedDecl>(*J); if (ND) { DeclContext* OldDC = ND->getDeclContext(); // Make sure the decl is not found at its old possition OldDC->removeDecl(ND); if (Scope* S = m_Sema->getScopeForContext(OldDC)) { S->RemoveDecl(ND); m_Sema->IdResolver.RemoveDecl(ND); } if (ND->getDeclContext() == ND->getLexicalDeclContext()) ND->setLexicalDeclContext(DC); else assert("Not implemented: Decl with different lexical context"); ND->setDeclContext(DC); if (VarDecl* VD = dyn_cast<VarDecl>(ND)) { VD->setStorageClass(SC_None); VD->setStorageClassAsWritten(SC_None); // if we want to print the result of the initializer of int i = 5 // or the default initializer int i if (I+1 == EI || !isa<NullStmt>(*(I+1))) { QualType VDTy = VD->getType().getNonReferenceType(); Expr* DRE = m_Sema->BuildDeclRefExpr(VD, VDTy,VK_LValue, SourceLocation() ).take(); Stmts.push_back(DRE); } } // force recalc of the linkage (to external) ND->ClearLinkageCache(); TouchedDecls.push_back(ND); } } } bool hasNoErrors = !CheckForClashingNames(TouchedDecls, DC, TUScope); if (hasNoErrors) { for (size_t i = 0; i < TouchedDecls.size(); ++i) { m_Sema->PushOnScopeChains(TouchedDecls[i], m_Sema->getScopeForContext(DC), /*AddCurContext*/!isa<UsingDirectiveDecl>(TouchedDecls[i])); // The transparent DeclContexts (eg. scopeless enum) doesn't have // scopes. While extracting their contents we need to update the // lookup tables and telling them to pick up the new possitions // in the AST. if (DeclContext* InnerDC = dyn_cast<DeclContext>(TouchedDecls[i])) { if (InnerDC->isTransparentContext()) { // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, InnerDC); for(DeclContext::decl_iterator DI = InnerDC->decls_begin(), DE = InnerDC->decls_end(); DI != DE ; ++DI) { if (NamedDecl* ND = dyn_cast<NamedDecl>(*DI)) InnerDC->makeDeclVisibleInContext(ND); } } } // Append the new top level decl to the current transaction. getTransaction()->appendUnique(DeclGroupRef(TouchedDecls[i])); } } CS->setStmts(*m_Context, Stmts.data(), Stmts.size()); // Put the wrapper after its declarations. (Nice when AST dumping) DC->removeDecl(FD); DC->addDecl(FD); return hasNoErrors; } return true; }
NewExpression(ASTType *t, Alloc all, std::list<Expression*> a, bool c, SourceLocation l = SourceLocation()) : Expression(l), type(t), alloc(all), args(a), call(c), function(NULL) {}
TupleExpression(std::vector<Expression*> e, SourceLocation l = SourceLocation()) : Expression(l), members(e) {}
DotPtrExpression(Expression *val, SourceLocation l = SourceLocation()) : Expression(l), lhs(val) {}
TypeExpression(ASTType *t, SourceLocation l = SourceLocation()) : Expression(l), type(t) {}
Expression(SourceLocation l = SourceLocation()) : Statement(l), value(NULL) {}
ModuleDeclaration(PackageDeclaration *parent, Identifier *id, std::string fn = "") : PackageDeclaration(parent, id, SourceLocation(filenm.c_str(), 1), DeclarationQualifier()), filenm(fn), expl(false) { importScope = new ASTScope(NULL, ASTScope::Scope_Global, this); }
SwitchStatement(ASTScope *sc, Expression *cond, Statement *b, SourceLocation l = SourceLocation()) : BlockStatement(sc, b, l), condition(cond) {}
If::If() : Element(std::shared_ptr<If_>(new If_()), SourceLocation()) { }
CastExpression(ASTType *ty, Expression *exp, SourceLocation l = SourceLocation()) : Expression(l), type(ty), expression(exp){}
Expr* ValueExtractionSynthesizer::SynthesizeSVRInit(Expr* E) { if (!m_gClingVD) FindAndCacheRuntimeDecls(); // Build a reference to gCling ExprResult gClingDRE = m_Sema->BuildDeclRefExpr(m_gClingVD, m_Context->VoidPtrTy, VK_RValue, SourceLocation()); // We have the wrapper as Sema's CurContext FunctionDecl* FD = cast<FunctionDecl>(m_Sema->CurContext); ExprWithCleanups* Cleanups = 0; // In case of ExprWithCleanups we need to extend its 'scope' to the call. if (E && isa<ExprWithCleanups>(E)) { Cleanups = cast<ExprWithCleanups>(E); E = Cleanups->getSubExpr(); } // Build a reference to Value* in the wrapper, should be // the only argument of the wrapper. SourceLocation locStart = (E) ? E->getLocStart() : FD->getLocStart(); SourceLocation locEnd = (E) ? E->getLocEnd() : FD->getLocEnd(); ExprResult wrapperSVRDRE = m_Sema->BuildDeclRefExpr(FD->getParamDecl(0), m_Context->VoidPtrTy, VK_RValue, locStart); QualType ETy = (E) ? E->getType() : m_Context->VoidTy; QualType desugaredTy = ETy.getDesugaredType(*m_Context); // The expr result is transported as reference, pointer, array, float etc // based on the desugared type. We should still expose the typedef'ed // (sugared) type to the cling::Value. if (desugaredTy->isRecordType() && E->getValueKind() == VK_LValue) { // returning a lvalue (not a temporary): the value should contain // a reference to the lvalue instead of copying it. desugaredTy = m_Context->getLValueReferenceType(desugaredTy); ETy = m_Context->getLValueReferenceType(ETy); } Expr* ETyVP = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy, (uintptr_t)ETy.getAsOpaquePtr()); // Pass whether to Value::dump() or not: Expr* EVPOn = new (*m_Context) CharacterLiteral(getCompilationOpts().ValuePrinting, CharacterLiteral::Ascii, m_Context->CharTy, SourceLocation()); llvm::SmallVector<Expr*, 6> CallArgs; CallArgs.push_back(gClingDRE.get()); CallArgs.push_back(wrapperSVRDRE.get()); CallArgs.push_back(ETyVP); CallArgs.push_back(EVPOn); ExprResult Call; SourceLocation noLoc = locStart; if (desugaredTy->isVoidType()) { // In cases where the cling::Value gets reused we need to reset the // previous settings to void. // We need to synthesize setValueNoAlloc(...), E, because we still need // to run E. // FIXME: Suboptimal: this discards the already created AST nodes. QualType vpQT = m_Context->VoidPtrTy; QualType vQT = m_Context->VoidTy; Expr* vpQTVP = utils::Synthesize::CStyleCastPtrExpr(m_Sema, vpQT, (uintptr_t)vQT.getAsOpaquePtr()); CallArgs[2] = vpQTVP; Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc, locStart, CallArgs, locEnd); if (E) Call = m_Sema->CreateBuiltinBinOp(locStart, BO_Comma, Call.get(), E); } else if (desugaredTy->isRecordType() || desugaredTy->isConstantArrayType() || desugaredTy->isMemberPointerType()) { // 2) object types : // check existence of copy constructor before call if (!desugaredTy->isMemberPointerType() && !availableCopyConstructor(desugaredTy, m_Sema)) return E; // call new (setValueWithAlloc(gCling, &SVR, ETy)) (E) Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedWithAlloc, locStart, CallArgs, locEnd); Expr* placement = Call.get(); if (const ConstantArrayType* constArray = dyn_cast<ConstantArrayType>(desugaredTy.getTypePtr())) { CallArgs.clear(); CallArgs.push_back(E); CallArgs.push_back(placement); size_t arrSize = m_Context->getConstantArrayElementCount(constArray); Expr* arrSizeExpr = utils::Synthesize::IntegerLiteralExpr(*m_Context, arrSize); CallArgs.push_back(arrSizeExpr); // 2.1) arrays: // call copyArray(T* src, void* placement, size_t size) Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedCopyArray, locStart, CallArgs, locEnd); } else { if (!E->getSourceRange().isValid()) { // We cannot do CXXNewExpr::CallInit (see Sema::BuildCXXNew) but // that's what we want. Fail... return E; } TypeSourceInfo* ETSI = m_Context->getTrivialTypeSourceInfo(ETy, noLoc); Call = m_Sema->BuildCXXNew(E->getSourceRange(), /*useGlobal ::*/true, /*placementLParen*/ noLoc, MultiExprArg(placement), /*placementRParen*/ noLoc, /*TypeIdParens*/ SourceRange(), /*allocType*/ ETSI->getType(), /*allocTypeInfo*/ETSI, /*arraySize*/0, /*directInitRange*/E->getSourceRange(), /*initializer*/E, /*mayContainAuto*/false ); // Handle possible cleanups: Call = m_Sema->ActOnFinishFullExpr(Call.get()); } } else { // Mark the current number of arguemnts const size_t nArgs = CallArgs.size(); if (desugaredTy->isIntegralOrEnumerationType()) { // 1) enum, integral, float, double, referece, pointer types : // call to cling::internal::setValueNoAlloc(...); // If the type is enum or integral we need to force-cast it into // uint64 in order to pick up the correct overload. if (desugaredTy->isIntegralOrEnumerationType()) { QualType UInt64Ty = m_Context->UnsignedLongLongTy; TypeSourceInfo* TSI = m_Context->getTrivialTypeSourceInfo(UInt64Ty, noLoc); Expr* castedE = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).get(); CallArgs.push_back(castedE); } } else if (desugaredTy->isReferenceType()) { // we need to get the address of the references Expr* AddrOfE = m_Sema->BuildUnaryOp(/*Scope*/0, noLoc, UO_AddrOf, E).get(); CallArgs.push_back(AddrOfE); } else if (desugaredTy->isAnyPointerType()) { // function pointers need explicit void* cast. QualType VoidPtrTy = m_Context->VoidPtrTy; TypeSourceInfo* TSI = m_Context->getTrivialTypeSourceInfo(VoidPtrTy, noLoc); Expr* castedE = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).get(); CallArgs.push_back(castedE); } else if (desugaredTy->isNullPtrType()) { // nullptr should decay to void* just fine. CallArgs.push_back(E); } else if (desugaredTy->isFloatingType()) { // floats and double will fall naturally in the correct // case, because of the overload resolution. CallArgs.push_back(E); } // Test CallArgs.size to make sure an additional argument (the value) // has been pushed on, if not than we didn't know how to handle the type if (CallArgs.size() > nArgs) { Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc, locStart, CallArgs, locEnd); } else { m_Sema->Diag(locStart, diag::err_unsupported_unknown_any_decl) << utils::TypeName::GetFullyQualifiedName(desugaredTy, *m_Context) << SourceRange(locStart, locEnd); } } assert(!Call.isInvalid() && "Invalid Call"); // Extend the scope of the temporary cleaner if applicable. if (Cleanups) { Cleanups->setSubExpr(Call.get()); Cleanups->setValueKind(Call.get()->getValueKind()); Cleanups->setType(Call.get()->getType()); return Cleanups; } return Call.get(); }
PostfixExpression(SourceLocation l = SourceLocation()) : Expression(l) {}
CompileErrorPair LexerPosition::error_loc(const PhysicalSourceLocation& loc) { return CompileErrorPair(*m_error_context, SourceLocation(loc, m_error_location)); }
FunctionExpression(FunctionDeclaration *ol, SourceLocation loc = SourceLocation()) : Expression(loc), overload(ol), fpointer(NULL) {}
ParseResult reduceTokenStr(ast::TokenStr &node) { const char* s = node.string().c_str(); return ParseResult(new Token(TK_None, s, SourceLocation())); }
FunctionExpression(Expression *fp, SourceLocation loc = SourceLocation()) : Expression(loc), overload(NULL), fpointer(fp) {}
Number::Number(double value) : Element(std::shared_ptr<Number_>(new Number_(value)), SourceLocation()) { SetFullyConstructed(true); }
CallExpression(Expression *f, std::list<Expression*> a, SourceLocation l = SourceLocation()) : PostfixExpression(l), function(f), resolvedFunction(NULL), args(a), isConstructor(false) {}
clang::StmtResult InsiemeSema::ActOnCompoundStmt(clang::SourceLocation L, clang::SourceLocation R, llvm::ArrayRef<clang::Stmt*> Elts, bool isStmtExpr) { // we parse the original code segment, within the original locations StmtResult&& ret = Sema::ActOnCompoundStmt(L, R, std::move(Elts), isStmtExpr); clang::CompoundStmt* CS = cast<clang::CompoundStmt>(ret.get()); // This is still buggy as of Clang 3.6.2: // when pragmas are just after the beginning of a compound stmt, example: // { // #pragma xxx // ... // } // the location of the opening bracket is wrong because of a bug in the clang parser. // // We solve the problem by searching for the bracket in the input stream and overwrite // the value of L (which contains the wrong location) with the correct value. enum { MacroIDBit = 1U << 31 }; // from clang/Basic/SourceLocation.h for use with cpp classes { SourceLocation&& leftBracketLoc = SourceMgr.getImmediateSpellingLoc(L); std::pair<FileID, unsigned>&& locInfo = SourceMgr.getDecomposedLoc(leftBracketLoc); llvm::StringRef&& buffer = SourceMgr.getBufferData(locInfo.first); const char* strData = buffer.begin() + locInfo.second; char const* lBracePos = strbchr(strData, buffer.begin(), '{'); // We know the location of the left bracket, we overwrite the value of L with the correct location // but only if the location is valid as in getFileLocWithOffset() in SourceLocation if((((leftBracketLoc.getRawEncoding() & ~MacroIDBit) + (lBracePos - strData)) & MacroIDBit) == 0) { L = leftBracketLoc.getLocWithOffset(lBracePos - strData); } } // For the right bracket, we start at the final statement in the compound // (or its start if it is empty) and search forward until we find the first "}" // Otherwise, cases such as this: // // { // bla(); // } // #pragma test expect_ir(R"( {} )") // // will be broken { SourceLocation rightBracketLoc; if(CS->size() == 0) { rightBracketLoc = SourceMgr.getImmediateSpellingLoc(L); } else { rightBracketLoc = SourceMgr.getImmediateSpellingLoc(CS->body_back()->getLocEnd()); } std::pair<FileID, unsigned>&& locInfo = SourceMgr.getDecomposedLoc(rightBracketLoc); llvm::StringRef buffer = SourceMgr.getBufferData(locInfo.first); const char* strData = buffer.begin() + locInfo.second; char const* rBracePos = strchr(strData, '}'); // We know the location of the right bracket, we overwrite the value of R with the correct location if((((rightBracketLoc.getRawEncoding() & ~MacroIDBit) + (rBracePos - strData)) & MacroIDBit) == 0) { R = rightBracketLoc.getLocWithOffset(rBracePos - strData); } } // the source range we inspect is defined by the new source locations, // this fix the problem with boundaries jumping to the beginning of the file in // the macro expansions: // // #define F(x) { } // // ... // // F(r) // <-this statement will jum to the macro location // PragmaList matched; SourceRange SR(L, R); // for each of the pragmas in the range between brackets for(PragmaFilter&& filter = PragmaFilter(SR, SourceMgr, pimpl->pending_pragma); *filter; ++filter) { PragmaPtr P = *filter; unsigned int pragmaStart = utils::Line(P->getStartLocation(), SourceMgr); unsigned int pragmaEnd = utils::Line(P->getEndLocation(), SourceMgr); bool found = false; // problem with first pragma, compound start is delayed until fist usable line (first stmt) if(CS->size() > 0) { for(clang::CompoundStmt::body_iterator it = CS->body_begin(); it != CS->body_end(); ++it) { unsigned int stmtStart = (Line((*it)->getLocStart(), SourceMgr)); if((pragmaEnd <= stmtStart)) { // ACHTUNG: if the node is a nullStmt, and is not at the end of the compound (in // which case is most probably ours) we can not trust it. semantics wont change, // we move one more. (BUG: nullStmt followed by pragmas, the source begin is // postponed until next stmt) this makes pragmas to be attached to a previous // stmt if(!llvm::isa<clang::NullStmt>(*it)) { // this pragma is attached to the current stmt P->setStatement(*it); matched.push_back(P); found = true; break; } } } } if(!found && pragmaStart <= utils::Line(R, SourceMgr)) { // this is a de-attached pragma (barrier i.e.) at the end of the compound // we need to create a fake NullStmt ( ; ) to attach this Stmt** stmts = new Stmt*[CS->size() + 1]; ArrayRef<clang::Stmt*> stmtList(stmts, CS->size() + 1); clang::CompoundStmt* newCS = new(Context) clang::CompoundStmt(Context, stmtList, CS->getSourceRange().getBegin(), CS->getSourceRange().getEnd()); std::copy(CS->body_begin(), CS->body_end(), newCS->body_begin()); std::for_each(CS->body_begin(), CS->body_end(), [&](Stmt*& curr) { this->Context.Deallocate(curr); }); newCS->setLastStmt(new(Context) NullStmt(SourceLocation())); P->setStatement(*newCS->body_rbegin()); matched.push_back(P); // transfer the ownership of the statement clang::CompoundStmt* oldStmt = ret.getAs<clang::CompoundStmt>(); oldStmt->setStmts(Context, NULL, 0); ret = newCS; CS = newCS; // destroy the old compound stmt Context.Deallocate(oldStmt); delete[] stmts; } } // remove matched pragmas EraseMatchedPragmas(pimpl->pending_pragma, matched); return std::move(ret); }
/** * @return a wrapper around the 1 nil object in the system. */ Element Nil_::Interpret_(Environment&) { return Nil(Nil_::instance, SourceLocation()); }
SourceLocation Cursor::getSourceLocation() const { return SourceLocation(clang().getCursorLocation(cursor())); }
Element Nil_::Lex_(CharacterStream& in) const { in.Consume(); return Nil(Nil_::instance, SourceLocation()); }
Evaluate::Evaluate(Strine const& strine) : Element(std::shared_ptr<Evaluate_>(new Evaluate_(strine)), SourceLocation()) { }
WhileStatement(ASTScope *sc, Expression *c, Statement *b, ElseStatement *e, SourceLocation l = SourceLocation()) : LoopStatement(sc, c, NULL, b, e, l) {}