bool RSContext::processExportFunc(const clang::FunctionDecl *FD) { slangAssert(!FD->getName().empty() && "Function name should not be empty"); if (!FD->isThisDeclarationADefinition()) { return true; } if (FD->getStorageClass() != clang::SC_None) { fprintf(stderr, "RSContext::processExportFunc : cannot export extern or " "static function '%s'\n", FD->getName().str().c_str()); return false; } if (RSExportForEach::isSpecialRSFunc(mTargetAPI, FD)) { // Do not reflect specialized functions like init, dtor, or graphics root. return RSExportForEach::validateSpecialFuncDecl(mTargetAPI, getDiagnostics(), FD); } else if (RSExportForEach::isRSForEachFunc(mTargetAPI, FD)) { RSExportForEach *EFE = RSExportForEach::Create(this, FD); if (EFE == NULL) return false; else mExportForEach.push_back(EFE); return true; } RSExportFunc *EF = RSExportFunc::Create(this, FD); if (EF == NULL) return false; else mExportFuncs.push_back(EF); return true; }
void SlangRS::initDiagnostic() { clang::DiagnosticsEngine &DiagEngine = getDiagnostics(); if (DiagEngine.setDiagnosticGroupMapping("implicit-function-declaration", clang::diag::MAP_ERROR)) DiagEngine.Report(clang::diag::warn_unknown_warning_option) << "implicit-function-declaration"; DiagEngine.setDiagnosticMapping( clang::diag::ext_typecheck_convert_discards_qualifiers, clang::diag::MAP_ERROR, clang::SourceLocation()); mDiagErrorInvalidOutputDepParameter = DiagEngine.getCustomDiagID( clang::DiagnosticsEngine::Error, "invalid parameter for output dependencies files."); mDiagErrorODR = DiagEngine.getCustomDiagID( clang::DiagnosticsEngine::Error, "type '%0' in different translation unit (%1 v.s. %2) " "has incompatible type definition"); mDiagErrorTargetAPIRange = DiagEngine.getCustomDiagID( clang::DiagnosticsEngine::Error, "target API level '%0' is out of range ('%1' - '%2')"); }
bool RSContext::reflectToJava(const std::string &OutputPathBase, const std::string &OutputPackageName, const std::string &InputFileName, const std::string &OutputBCFileName, std::string *RealPackageName) { if (RealPackageName != NULL) RealPackageName->clear(); const std::string &PackageName = ((OutputPackageName.empty()) ? mReflectJavaPackageName : OutputPackageName); if (PackageName.empty()) { clang::DiagnosticsEngine *DiagEngine = getDiagnostics(); const clang::SourceManager *SM = getSourceManager(); DiagEngine->Report( SM->getLocForEndOfFile(SM->getMainFileID()), DiagEngine->getCustomDiagID(clang::DiagnosticsEngine::Error, "missing \"#pragma rs " "java_package_name(com.foo.bar)\" " "in source file")); return false; } // Copy back the really applied package name RealPackageName->assign(PackageName); RSReflection *R = new RSReflection(this, mGeneratedFileNames); bool ret = R->reflect(OutputPathBase, PackageName, InputFileName, OutputBCFileName); if (!ret) fprintf(stderr, "RSContext::reflectToJava : failed to do reflection " "(%s)\n", R->getLastError()); delete R; return ret; }
std::unique_ptr<CompilerInstance> prepareCompilerInstance(std::unique_ptr<clang::CompilerInvocation> CI, const PrecompiledPreamble *Preamble, std::unique_ptr<llvm::MemoryBuffer> Buffer, std::shared_ptr<PCHContainerOperations> PCHs, IntrusiveRefCntPtr<vfs::FileSystem> VFS, DiagnosticConsumer &DiagsClient) { assert(VFS && "VFS is null"); assert(!CI->getPreprocessorOpts().RetainRemappedFileBuffers && "Setting RetainRemappedFileBuffers to true will cause a memory leak " "of ContentsBuffer"); // NOTE: we use Buffer.get() when adding remapped files, so we have to make // sure it will be released if no error is emitted. if (Preamble) { Preamble->OverridePreamble(*CI, VFS, Buffer.get()); } else { CI->getPreprocessorOpts().addRemappedFile( CI->getFrontendOpts().Inputs[0].getFile(), Buffer.get()); } auto Clang = llvm::make_unique<CompilerInstance>(PCHs); Clang->setInvocation(std::move(CI)); Clang->createDiagnostics(&DiagsClient, false); if (auto VFSWithRemapping = createVFSFromCompilerInvocation( Clang->getInvocation(), Clang->getDiagnostics(), VFS)) VFS = VFSWithRemapping; Clang->setVirtualFileSystem(VFS); Clang->setTarget(TargetInfo::CreateTargetInfo( Clang->getDiagnostics(), Clang->getInvocation().TargetOpts)); if (!Clang->hasTarget()) return nullptr; // RemappedFileBuffers will handle the lifetime of the Buffer pointer, // release it. Buffer.release(); return Clang; }
std::unique_ptr<CompilerInstance> BuildCompilerInstance(ArrayRef<const char *> ClangArgv) { auto Ins = llvm::make_unique<CompilerInstance>(); auto DC = llvm::make_unique<TestDiagnosticConsumer>(); const bool ShouldOwnClient = true; Ins->createDiagnostics(DC.release(), ShouldOwnClient); auto Inv = llvm::make_unique<CompilerInvocation>(); CompilerInvocation::CreateFromArgs(*Inv, ClangArgv.data(), &ClangArgv.data()[ClangArgv.size()], Ins->getDiagnostics()); Inv->getLangOpts()->CPlusPlus = true; Inv->getLangOpts()->CPlusPlus11 = true; Inv->getHeaderSearchOpts().UseLibcxx = true; Inv->getLangOpts()->Bool = true; Inv->getLangOpts()->WChar = true; Inv->getLangOpts()->Blocks = true; Inv->getLangOpts()->DebuggerSupport = true; Inv->getLangOpts()->SpellChecking = false; Inv->getLangOpts()->ThreadsafeStatics = false; Inv->getLangOpts()->AccessControl = false; Inv->getLangOpts()->DollarIdents = true; Inv->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo); Inv->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple(); Ins->setInvocation(Inv.release()); TargetInfo *TI = TargetInfo::CreateTargetInfo( Ins->getDiagnostics(), Ins->getInvocation().TargetOpts); Ins->setTarget(TI); Ins->getTarget().adjust(Ins->getLangOpts()); Ins->createFileManager(); Ins->createSourceManager(Ins->getFileManager()); Ins->createPreprocessor(TU_Complete); return Ins; }
clang::ASTConsumer *SlangRS::createBackend(const clang::CodeGenOptions& CodeGenOpts, llvm::raw_ostream *OS, Slang::OutputType OT) { return new RSBackend(mRSContext, &getDiagnostics(), CodeGenOpts, getTargetOptions(), &mPragmas, OS, OT, getSourceManager(), mAllowRSPrefix); }
bool RSContext::processExport() { bool valid = true; if (getDiagnostics()->hasErrorOccurred()) { return false; } // Export variable clang::TranslationUnitDecl *TUDecl = mCtx.getTranslationUnitDecl(); for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(), DE = TUDecl->decls_end(); DI != DE; DI++) { if (DI->getKind() == clang::Decl::Var) { clang::VarDecl *VD = (clang::VarDecl*) (*DI); if (VD->getFormalLinkage() == clang::ExternalLinkage) { if (!processExportVar(VD)) { valid = false; } } } else if (DI->getKind() == clang::Decl::Function) { // Export functions clang::FunctionDecl *FD = (clang::FunctionDecl*) (*DI); if (FD->getFormalLinkage() == clang::ExternalLinkage) { if (!processExportFunc(FD)) { valid = false; } } } } if (valid) { cleanupForEach(); } // Finally, export type forcely set to be exported by user for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(), EE = mNeedExportTypes.end(); EI != EE; EI++) { if (!processExportType(EI->getKey())) { valid = false; } } return valid; }
bool SlangRS::checkODR(const char *CurInputFile) { for (RSContext::ExportableList::iterator I = mRSContext->exportable_begin(), E = mRSContext->exportable_end(); I != E; I++) { RSExportable *RSE = *I; if (RSE->getKind() != RSExportable::EX_TYPE) continue; RSExportType *ET = static_cast<RSExportType *>(RSE); if (ET->getClass() != RSExportType::ExportClassRecord) continue; RSExportRecordType *ERT = static_cast<RSExportRecordType *>(ET); // Artificial record types (create by us not by user in the source) always // conforms the ODR. if (ERT->isArtificial()) continue; // Key to lookup ERT in ReflectedDefinitions llvm::StringRef RDKey(ERT->getName()); ReflectedDefinitionListTy::const_iterator RD = ReflectedDefinitions.find(RDKey); if (RD != ReflectedDefinitions.end()) { const RSExportRecordType *Reflected = RD->getValue().first; // There's a record (struct) with the same name reflected before. Enforce // ODR checking - the Reflected must hold *exactly* the same "definition" // as the one defined previously. We say two record types A and B have the // same definition iff: // // struct A { struct B { // Type(a1) a1, Type(b1) b1, // Type(a2) a2, Type(b1) b2, // ... ... // Type(aN) aN Type(b3) b3, // }; } // Cond. #1. They have same number of fields, i.e., N = M; // Cond. #2. for (i := 1 to N) // Type(ai) = Type(bi) must hold; // Cond. #3. for (i := 1 to N) // Name(ai) = Name(bi) must hold; // // where, // Type(F) = the type of field F and // Name(F) = the field name. bool PassODR = false; // Cond. #1 and Cond. #2 if (Reflected->equals(ERT)) { // Cond #3. RSExportRecordType::const_field_iterator AI = Reflected->fields_begin(), BI = ERT->fields_begin(); for (unsigned i = 0, e = Reflected->getFields().size(); i != e; i++) { if ((*AI)->getName() != (*BI)->getName()) break; AI++; BI++; } PassODR = (AI == (Reflected->fields_end())); } if (!PassODR) { getDiagnostics().Report(mDiagErrorODR) << Reflected->getName() << getInputFileName() << RD->getValue().second; return false; } } else { llvm::StringMapEntry<ReflectedDefinitionTy> *ME = llvm::StringMapEntry<ReflectedDefinitionTy>::Create(RDKey.begin(), RDKey.end()); ME->setValue(std::make_pair(ERT, CurInputFile)); if (!ReflectedDefinitions.insert(ME)) delete ME; // Take the ownership of ERT such that it won't be freed in ~RSContext(). ERT->keep(); } } return true; }