void ReturnSynthesizer::Transform() { if (!getTransaction()->getCompilationOpts().ResultEvaluation) return; FunctionDecl* FD = getTransaction()->getWrapperFD(); int foundAtPos = -1; Expr* lastExpr = utils::Analyze::GetOrCreateLastExpr(FD, &foundAtPos, /*omitDS*/false, m_Sema); if (lastExpr) { QualType RetTy = lastExpr->getType(); if (!RetTy->isVoidType() && RetTy.isTriviallyCopyableType(*m_Context)) { // Change the void function's return type // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, FD); FunctionProtoType::ExtProtoInfo EPI; QualType FnTy = m_Context->getFunctionType(RetTy, llvm::ArrayRef<QualType>(), EPI); FD->setType(FnTy); CompoundStmt* CS = cast<CompoundStmt>(FD->getBody()); assert(CS && "Missing body?"); // Change it to a return stmt (Avoid dealloc/alloc of all el.) *(CS->body_begin() + foundAtPos) = m_Sema->ActOnReturnStmt(lastExpr->getExprLoc(), lastExpr).take(); } } else if (foundAtPos >= 0) { // check for non-void return statement CompoundStmt* CS = cast<CompoundStmt>(FD->getBody()); Stmt* CSS = *(CS->body_begin() + foundAtPos); if (ReturnStmt* RS = dyn_cast<ReturnStmt>(CSS)) { if (Expr* RetV = RS->getRetValue()) { QualType RetTy = RetV->getType(); // Any return statement will have been "healed" by Sema // to correspond to the original void return type of the // wrapper, using a ImplicitCastExpr 'void' <ToVoid>. // Remove that. if (RetTy->isVoidType()) { ImplicitCastExpr* VoidCast = dyn_cast<ImplicitCastExpr>(RetV); if (VoidCast) { RS->setRetValue(VoidCast->getSubExpr()); RetTy = VoidCast->getSubExpr()->getType(); } } if (!RetTy->isVoidType() && RetTy.isTriviallyCopyableType(*m_Context)) { Sema::ContextRAII pushedDC(*m_Sema, FD); FunctionProtoType::ExtProtoInfo EPI; QualType FnTy = m_Context->getFunctionType(RetTy, llvm::ArrayRef<QualType>(), EPI); FD->setType(FnTy); } // not returning void } // have return value } // is a return statement } // have a statement }
void VisitCallExpr(CallExpr* CE) { Visit(CE->getCallee()); FunctionDecl* FDecl = CE->getDirectCallee(); if (FDecl && isDeclCandidate(FDecl)) { decl_map_t::const_iterator it = m_NonNullArgIndexs.find(FDecl); const std::bitset<32>& ArgIndexs = it->second; Sema::ContextRAII pushedDC(m_Sema, FDecl); for (int index = 0; index < 32; ++index) { if (ArgIndexs.test(index)) { // Get the argument with the nonnull attribute. Expr* Arg = CE->getArg(index); CE->setArg(index, SynthesizeCheck(Arg)); } } } }
bool VisitCallExpr(CallExpr* CE) { VisitStmt(CE->getCallee()); FunctionDecl* FDecl = CE->getDirectCallee(); if (FDecl && isDeclCandidate(FDecl)) { decl_map_t::const_iterator it = m_NonNullArgIndexs.find(FDecl); const std::bitset<32>& ArgIndexs = it->second; Sema::ContextRAII pushedDC(m_Sema, FDecl); for (int index = 0; index < 32; ++index) { if (ArgIndexs.test(index)) { // Get the argument with the nonnull attribute. Expr* Arg = CE->getArg(index); if (Arg->getType().getTypePtr()->isPointerType() && !llvm::isa<clang::CXXThisExpr>(Arg)) CE->setArg(index, SynthesizeCheck(Arg)); } } } return true; }
void ValueExtractionSynthesizer::Transform() { const CompilationOptions& CO = getTransaction()->getCompilationOpts(); // If we do not evaluate the result, or printing out the result return. if (!(CO.ResultEvaluation || CO.ValuePrinting)) return; FunctionDecl* FD = getTransaction()->getWrapperFD(); int foundAtPos = -1; Expr* lastExpr = utils::Analyze::GetOrCreateLastExpr(FD, &foundAtPos, /*omitDS*/false, m_Sema); if (foundAtPos < 0) return; typedef llvm::SmallVector<Stmt**, 4> StmtIters; StmtIters returnStmts; ReturnStmtCollector collector(returnStmts); CompoundStmt* CS = cast<CompoundStmt>(FD->getBody()); collector.VisitStmt(CS); if (isa<Expr>(*(CS->body_begin() + foundAtPos))) returnStmts.push_back(CS->body_begin() + foundAtPos); // We want to support cases such as: // gCling->evaluate("if() return 'A' else return 12", V), that puts in V, // either A or 12. // In this case the void wrapper is compiled with the stmts returning // values. Sema would cast them to void, but the code will still be // executed. For example: // int g(); void f () { return g(); } will still call g(). // for (StmtIters::iterator I = returnStmts.begin(), E = returnStmts.end(); I != E; ++I) { ReturnStmt* RS = dyn_cast<ReturnStmt>(**I); if (RS) { // When we are handling a return stmt, the last expression must be the // return stmt value. Ignore the calculation of the lastStmt because it // might be wrong, in cases where the return is not in the end of the // function. lastExpr = RS->getRetValue(); if (lastExpr) { assert (lastExpr->getType()->isVoidType() && "Must be void type."); // Any return statement will have been "healed" by Sema // to correspond to the original void return type of the // wrapper, using a ImplicitCastExpr 'void' <ToVoid>. // Remove that. if (ImplicitCastExpr* VoidCast = dyn_cast<ImplicitCastExpr>(lastExpr)) { lastExpr = VoidCast->getSubExpr(); } } // if no value assume void else { // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, FD); RS->setRetValue(SynthesizeSVRInit(0)); } } else lastExpr = cast<Expr>(**I); if (lastExpr) { QualType lastExprTy = lastExpr->getType(); // May happen on auto types which resolve to dependent. if (lastExprTy->isDependentType()) continue; // Set up lastExpr properly. // Change the void function's return type // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, FD); if (lastExprTy->isFunctionType()) { // A return type of function needs to be converted to // pointer to function. lastExprTy = m_Context->getPointerType(lastExprTy); lastExpr = m_Sema->ImpCastExprToType(lastExpr, lastExprTy, CK_FunctionToPointerDecay, VK_RValue).take(); } // // Here we don't want to depend on the JIT runFunction, because of its // limitations, when it comes to return value handling. There it is // not clear who provides the storage and who cleans it up in a // platform independent way. // // Depending on the type we need to synthesize a call to cling: // 0) void : set the value's type to void; // 1) enum, integral, float, double, referece, pointer types : // call to cling::internal::setValueNoAlloc(...); // 2) object type (alloc on the stack) : // cling::internal::setValueWithAlloc // 2.1) constant arrays: // call to cling::runtime::internal::copyArray(...) // // We need to synthesize later: // Wrapper has signature: void w(cling::Value SVR) // case 1): // setValueNoAlloc(gCling, &SVR, lastExprTy, lastExpr()) // case 2): // new (setValueWithAlloc(gCling, &SVR, lastExprTy)) (lastExpr) // case 2.1): // copyArray(src, placement, size) Expr* SVRInit = SynthesizeSVRInit(lastExpr); // if we had return stmt update to execute the SVR init, even if the // wrapper returns void. if (RS) { if (ImplicitCastExpr* VoidCast = dyn_cast<ImplicitCastExpr>(RS->getRetValue())) VoidCast->setSubExpr(SVRInit); } else **I = SVRInit; } } }
bool DeclExtractor::ExtractDecl(FunctionDecl* FD) { 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 (isa<UsingDirectiveDecl>(*J)) continue; // FIXME: Here we should be more elegant. if (ND) { if (Stmts.size()) { // We need to emit a new custom wrapper wrapping the stmts EnforceInitOrder(Stmts); assert(!Stmts.size() && "Stmt list must be flushed."); } // We know the transaction is closed, but it is safe. getTransaction()->forceAppend(ND); DeclContext* OldDC = ND->getDeclContext(); // Make sure the decl is not found at its old possition ND->getLexicalDeclContext()->removeDecl(ND); if (Scope* S = m_Sema->getScopeForContext(OldDC)) { S->RemoveDecl(ND); if (utils::Analyze::isOnScopeChains(ND, *m_Sema)) m_Sema->IdResolver.RemoveDecl(ND); } // For variable definitions causing var/function ambiguity such as: // MyClass my();, C++ standard says it shall be resolved as a function // // In the particular context this definition is inside a function // already, but clang thinks it as a lambda, so we need to ignore the // check decl context vs lexical decl context. if (ND->getDeclContext() == ND->getLexicalDeclContext() || isa<FunctionDecl>(ND)) ND->setLexicalDeclContext(DC); else assert(0 && "Not implemented: Decl with different lexical context"); ND->setDeclContext(DC); if (VarDecl* VD = dyn_cast<VarDecl>(ND)) { VD->setStorageClass(SC_None); } clearLinkage(ND); TouchedDecls.push_back(ND); } } } bool hasNoErrors = !CheckForClashingNames(TouchedDecls, DC, TUScope); if (hasNoErrors) { for (size_t i = 0; i < TouchedDecls.size(); ++i) { // We should skip the checks for annonymous decls and we should not // register them in the lookup. if (!TouchedDecls[i]->getDeclName()) continue; 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); } } } } } CS->setStmts(*m_Context, Stmts.data(), Stmts.size()); // The order matters, because when we extract decls from the wrapper we // append them to the transaction. If the transaction gets unloaded it will // introduce a fake dependency, so put the move last. Transaction* T = getTransaction(); for (Transaction::iterator I = T->decls_begin(), E = T->decls_end(); I != E; ++I) if (!I->m_DGR.isNull() && I->m_DGR.isSingleDecl() && I->m_DGR.getSingleDecl() == T->getWrapperFD()) { T->erase(I); break; } T->forceAppend(FD); // Put the wrapper after its declarations. (Nice when AST dumping) DC->removeDecl(FD); DC->addDecl(FD); return hasNoErrors; }
void DeclExtractor::EnforceInitOrder(llvm::SmallVectorImpl<Stmt*>& Stmts){ Scope* TUScope = m_Sema->TUScope; DeclContext* TUDC = static_cast<DeclContext*>(TUScope->getEntity()); // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, TUDC); std::string FunctionName = "__fd"; createUniqueName(FunctionName); IdentifierInfo& IIFD = m_Context->Idents.get(FunctionName); SourceLocation Loc; NamedDecl* ND = m_Sema->ImplicitlyDefineFunction(Loc, IIFD, TUScope); if (FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(ND)) { FD->setImplicit(false); // Better for debugging // Add a return statement if it doesn't exist if (!isa<ReturnStmt>(Stmts.back())) { Sema::ContextRAII pushedDC(*m_Sema, FD); // Generate the return statement: // First a literal 0, then the return taking that literal. // One bit is enough: llvm::APInt ZeroInt(m_Context->getIntWidth(m_Context->IntTy), 0, /*isSigned=*/true); IntegerLiteral* ZeroLit = IntegerLiteral::Create(*m_Context, ZeroInt, m_Context->IntTy, SourceLocation()); Stmts.push_back(m_Sema->ActOnReturnStmt(ZeroLit->getExprLoc(), ZeroLit).take()); } // Wrap Stmts into a function body. llvm::ArrayRef<Stmt*> StmtsRef(Stmts.data(), Stmts.size()); CompoundStmt* CS = new (*m_Context)CompoundStmt(*m_Context, StmtsRef, Loc, Loc); FD->setBody(CS); // We know the transaction is closed, but it is safe. getTransaction()->forceAppend(FD); // Create the VarDecl with the init std::string VarName = "__vd"; createUniqueName(VarName); IdentifierInfo& IIVD = m_Context->Idents.get(VarName); VarDecl* VD = VarDecl::Create(*m_Context, TUDC, Loc, Loc, &IIVD, FD->getReturnType(), (TypeSourceInfo*)0, SC_None); LookupResult R(*m_Sema, FD->getDeclName(), Loc, Sema::LookupMemberName); R.addDecl(FD); CXXScopeSpec CSS; Expr* UnresolvedLookup = m_Sema->BuildDeclarationNameExpr(CSS, R, /*ADL*/ false).take(); Expr* TheCall = m_Sema->ActOnCallExpr(TUScope, UnresolvedLookup, Loc, MultiExprArg(), Loc).take(); assert(VD && TheCall && "Missing VD or its init!"); VD->setInit(TheCall); // We know the transaction is closed, but it is safe. getTransaction()->forceAppend(VD); // Add it to the transaction for codegenning TUDC->addHiddenDecl(VD); Stmts.clear(); return; } llvm_unreachable("Must be able to enforce init order."); }
bool ValuePrinterSynthesizer::tryAttachVP(FunctionDecl* FD) { // We have to be able to mark the expression for printout. There are // three scenarios: // 0: Expression printing disabled - don't do anything just exit. // 1: Expression printing enabled - print no matter what. // 2: Expression printing auto - analyze - rely on the omitted ';' to // not produce the suppress marker. int indexOfLastExpr = -1; Expr* To = utils::Analyze::GetOrCreateLastExpr(FD, &indexOfLastExpr, /*omitDS*/false, m_Sema); if (To) { // Update the CompoundStmt body, avoiding alloc/dealloc of all the el. CompoundStmt* CS = cast<CompoundStmt>(FD->getBody()); assert(CS && "Missing body?"); switch (getCompilationOpts().ValuePrinting) { case CompilationOptions::VPDisabled: assert(0 && "Don't wait that long. Exit early!"); break; case CompilationOptions::VPEnabled: break; case CompilationOptions::VPAuto: { // FIXME: Propagate the flag to the nested transactions also, they // must have the same CO as their parents. getCompilationOpts().ValuePrinting = CompilationOptions::VPEnabled; if ((int)CS->size() > indexOfLastExpr+1 && (*(CS->body_begin() + indexOfLastExpr + 1)) && isa<NullStmt>(*(CS->body_begin() + indexOfLastExpr + 1))) { // If next is NullStmt disable VP is disabled - exit. Signal this in // the CO of the transaction. getCompilationOpts().ValuePrinting = CompilationOptions::VPDisabled; } if (getCompilationOpts().ValuePrinting == CompilationOptions::VPDisabled) return true; } break; } // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*m_Sema, FD); if (To) { // Strip the parenthesis if any if (ParenExpr* PE = dyn_cast<ParenExpr>(To)) To = PE->getSubExpr(); Expr* Result = 0; // if (!m_Sema->getLangOpts().CPlusPlus) // Result = SynthesizeVP(To); if (Result) *(CS->body_begin()+indexOfLastExpr) = Result; } // Clear the artificial NullStmt-s if (!ClearNullStmts(CS)) { // FIXME: Why it is here? Shouldn't it be in DeclExtractor? // if no body remove the wrapper DeclContext* DC = FD->getDeclContext(); Scope* S = m_Sema->getScopeForContext(DC); if (S) S->RemoveDecl(FD); DC->removeDecl(FD); } } else // if nothing to attach to set the CO's ValuePrinting to disabled. getCompilationOpts().ValuePrinting = CompilationOptions::VPDisabled; return true; }
Expr* EvaluateTSynthesizer::BuildDynamicExprInfo(Expr* SubTree, bool ValuePrinterReq) { // We need to evaluate it in its own context. Evaluation on the global // scope per se can break for example the compound literals, which have // to be constants (see [C99 6.5.2.5]) Sema::ContextRAII pushedDC(*m_Sema, m_CurDeclContext); // 1. Get the expression containing @-s and get the variable addresses std::string Template; llvm::SmallVector<DeclRefExpr*, 4> Addresses; llvm::raw_string_ostream OS(Template); const PrintingPolicy& Policy = m_Context->getPrintingPolicy(); StmtPrinterHelper helper(Policy, Addresses, m_Sema); // In case when we print non paren inits like int i = h->Draw(); // not int i(h->Draw()). This simplifies the LifetimeHandler's // constructor, there we don't need to add parenthesis while // wrapping the expression. if (!isa<ParenListExpr>(SubTree)) OS << '('; SubTree->printPretty(OS, &helper, Policy); if (!isa<ParenListExpr>(SubTree)) OS << ')'; OS.flush(); // 2. Build the template Expr* ExprTemplate = ConstructConstCharPtrExpr(Template.c_str()); // 3. Build the array of addresses QualType VarAddrTy = m_Sema->BuildArrayType(m_Context->VoidPtrTy, ArrayType::Normal, /*ArraySize*/0, /*IndexTypeQuals*/0, m_NoRange, DeclarationName() ); llvm::SmallVector<Expr*, 2> Inits; Scope* S = m_Sema->getScopeForContext(m_Sema->CurContext); for (unsigned int i = 0; i < Addresses.size(); ++i) { Expr* UnOp = m_Sema->BuildUnaryOp(S, m_NoSLoc, UO_AddrOf, Addresses[i]).take(); m_Sema->ImpCastExprToType(UnOp, m_Context->getPointerType(m_Context->VoidPtrTy), CK_BitCast); Inits.push_back(UnOp); } // We need valid source locations to avoid assert(InitList.isExplicit()...) InitListExpr* ILE = m_Sema->ActOnInitList(m_NoSLoc, Inits, m_NoELoc).takeAs<InitListExpr>(); TypeSourceInfo* TSI = m_Context->getTrivialTypeSourceInfo(VarAddrTy, m_NoSLoc); Expr* ExprAddresses = m_Sema->BuildCompoundLiteralExpr(m_NoSLoc, TSI, m_NoELoc, ILE).take(); assert (ExprAddresses && "Could not build the void* array"); m_Sema->ImpCastExprToType(ExprAddresses, m_Context->getPointerType(m_Context->VoidPtrTy), CK_ArrayToPointerDecay); // Is the result of the expression to be printed or not Expr* VPReq = 0; if (ValuePrinterReq) VPReq = m_Sema->ActOnCXXBoolLiteral(m_NoSLoc, tok::kw_true).take(); else VPReq = m_Sema->ActOnCXXBoolLiteral(m_NoSLoc, tok::kw_false).take(); llvm::SmallVector<Expr*, 4> CtorArgs; CtorArgs.push_back(ExprTemplate); CtorArgs.push_back(ExprAddresses); CtorArgs.push_back(VPReq); // 4. Call the constructor QualType ExprInfoTy = m_Context->getTypeDeclType(m_DynamicExprInfoDecl); ExprResult Initializer = m_Sema->ActOnParenListExpr(m_NoSLoc, m_NoELoc, CtorArgs); TypeSourceInfo* TrivialTSI = m_Context->getTrivialTypeSourceInfo(ExprInfoTy, SourceLocation()); Expr* Result = m_Sema->BuildCXXNew(m_NoSLoc, /*UseGlobal=*/false, m_NoSLoc, /*PlacementArgs=*/MultiExprArg(), m_NoELoc, m_NoRange, ExprInfoTy, TrivialTSI, /*ArraySize=*/0, //BuildCXXNew depends on the SLoc to be //valid! // TODO: Propose a patch in clang m_NoRange, Initializer.take(), /*TypeMayContainAuto*/false ).take(); return Result; }
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; }