clang::Decl* InsiemeSema::ActOnFinishFunctionBody(clang::Decl* Decl, clang::Stmt* Body) { VLOG(2) << "{InsiemeSema}: ActOnFinishFunctionBody()"; clang::Decl* ret = Sema::ActOnFinishFunctionBody(Decl, std::move(Body)); // We are sure all the pragmas inside the function body have been matched FunctionDecl* FD = dyn_cast<FunctionDecl>(ret); if(!FD) { return ret; } PragmaList matched; std::list<PragmaPtr>::reverse_iterator I = pimpl->pending_pragma.rbegin(), E = pimpl->pending_pragma.rend(); while(I != E && isAfterRange(FD->getSourceRange(), (*I)->getStartLocation(), SourceMgr)) { ++I; } while(I != E) { unsigned int pragmaEnd = utils::Line((*I)->getEndLocation(), SourceMgr); unsigned int declBegin = utils::Line(ret->getSourceRange().getBegin(), SourceMgr); if(pragmaEnd <= declBegin) { (*I)->setDecl(FD); matched.push_back(*I); } ++I; } EraseMatchedPragmas(pimpl->pending_pragma, matched); isInsideFunctionDef = false; return ret; }
void InsiemeSema::matchStmt(clang::Stmt* S, const clang::SourceRange& bounds, const clang::SourceManager& sm, PragmaList& matched) { for(PragmaFilter filter(bounds, sm, pimpl->pending_pragma); *filter; ++filter) { PragmaPtr&& P = *filter; P->setStatement(S); matched.push_back(P); } }
SgNodeHelper::PragmaList SgNodeHelper::collectPragmaLines(string pragmaName,SgNode* root) { PragmaList l; RoseAst ast(root); for(RoseAst::iterator i=ast.begin();i!=ast.end();++i) { std::list<SgPragmaDeclaration*> pragmaNodes; ROSE_ASSERT(pragmaNodes.size()==0); // SgPragmaDeclaration(SgPragma),..., SgStatement // collects consecutive pragma declarations while(i!=ast.end()&&(isSgPragmaDeclaration(*i)||isSgPragma(*i))) { if(SgPragmaDeclaration* pragmaDecl=isSgPragmaDeclaration(*i)) { pragmaNodes.push_back(pragmaDecl); } ++i; } if(i!=ast.end()) { for(std::list<SgPragmaDeclaration*>::iterator p=pragmaNodes.begin();p!=pragmaNodes.end();++p) { string str=SgNodeHelper::getPragmaDeclarationString(*p); SgNodeHelper::replaceString(str,"#pragma ",""); if(SgNodeHelper::isPrefix(pragmaName,str)) { SgPragmaDeclaration* lastPragmaDecl=pragmaNodes.back(); // ensure we did not collect pragmas at the end of a block if(!(isLastChildOf(lastPragmaDecl,lastPragmaDecl->get_parent()))) { if(SgStatement* assocStmt=isSgStatement(*i)) { SgNodeHelper::replaceString(str,pragmaName+" ",""); //cout<<"PRAGMA REVERSE: "<<str<<" : "<<(assocStmt)->unparseToString()<<endl; l.push_back(make_pair(str,assocStmt)); } else { std::cerr<<"Error: "<<SgNodeHelper::sourceLineColumnToString(*p)<<": reverse pragma not associated with a method or statement."<<endl <<"Pragma : "<<str<<endl <<"Associated code: "<<assocStmt->unparseToString()<<endl; exit(1); } } else { std::cerr<<"Error: "<<SgNodeHelper::sourceLineColumnToString(*p)<<": pragma at end of block. This is not allowed."<<endl; exit(1); } } } } } return l; }
void InsiemeSema::ActOnTagFinishDefinition(clang::Scope* S, clang::Decl* TagDecl, clang::SourceLocation RBraceLoc) { VLOG(2) << "{InsiemeSema}: ActOnTagFinishDefinition()"; Sema::ActOnTagFinishDefinition(S, TagDecl, RBraceLoc); if(isInsideFunctionDef) { return; } PragmaList matched; std::list<PragmaPtr>::reverse_iterator I = pimpl->pending_pragma.rbegin(), E = pimpl->pending_pragma.rend(); while(I != E && isAfterRange(TagDecl->getSourceRange(), (*I)->getStartLocation(), SourceMgr)) { ++I; } while(I != E) { (*I)->setDecl(TagDecl); matched.push_back(*I); ++I; } EraseMatchedPragmas(pimpl->pending_pragma, matched); }
clang::Decl* InsiemeSema::ActOnDeclarator(clang::Scope* S, clang::Declarator& D) { VLOG(2) << "{InsiemeSema}: ActOnDeclarator()"; clang::Decl* ret = Sema::ActOnDeclarator(S, D); if(isInsideFunctionDef) { return ret; } PragmaList matched; std::list<PragmaPtr>::reverse_iterator I = pimpl->pending_pragma.rbegin(), E = pimpl->pending_pragma.rend(); while(I != E && isAfterRange(ret->getSourceRange(), (*I)->getStartLocation(), SourceMgr)) { ++I; } while(I != E) { (*I)->setDecl(ret); matched.push_back(*I); ++I; } EraseMatchedPragmas(pimpl->pending_pragma, matched); return ret; }
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); }