RSExportFunc *RSExportFunc::Create(RSContext *Context, const clang::FunctionDecl *FD) { llvm::StringRef Name = FD->getName(); RSExportFunc *F; slangAssert(!Name.empty() && "Function must have a name"); if (!ValidateFuncDecl(Context->getDiagnostics(), FD)) { return NULL; } F = new RSExportFunc(Context, Name, FD); // Initialize mParamPacketType if (FD->getNumParams() <= 0) { F->mParamPacketType = NULL; } else { clang::ASTContext &Ctx = Context->getASTContext(); std::string Id(DUMMY_RS_TYPE_NAME_PREFIX"helper_func_param:"); Id.append(F->getName()).append(DUMMY_RS_TYPE_NAME_POSTFIX); clang::RecordDecl *RD = clang::RecordDecl::Create(Ctx, clang::TTK_Struct, Ctx.getTranslationUnitDecl(), clang::SourceLocation(), clang::SourceLocation(), &Ctx.Idents.get(Id)); for (unsigned i = 0; i < FD->getNumParams(); i++) { const clang::ParmVarDecl *PVD = FD->getParamDecl(i); llvm::StringRef ParamName = PVD->getName(); if (PVD->hasDefaultArg()) fprintf(stderr, "Note: parameter '%s' in function '%s' has default " "value which is not supported\n", ParamName.str().c_str(), F->getName().c_str()); clang::FieldDecl *FD = clang::FieldDecl::Create(Ctx, RD, clang::SourceLocation(), clang::SourceLocation(), PVD->getIdentifier(), PVD->getOriginalType(), NULL, /* BitWidth = */ NULL, /* Mutable = */ false, /* HasInit = */ false); RD->addDecl(FD); } RD->completeDefinition(); clang::QualType T = Ctx.getTagDeclType(RD); slangAssert(!T.isNull()); RSExportType *ET = RSExportType::Create(Context, T.getTypePtr()); if (ET == NULL) { fprintf(stderr, "Failed to export the function %s. There's at least one " "parameter whose type is not supported by the " "reflection\n", F->getName().c_str()); return NULL; } slangAssert((ET->getClass() == RSExportType::ExportClassRecord) && "Parameter packet must be a record"); F->mParamPacketType = static_cast<RSExportRecordType *>(ET); } return F; }
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; }
RSExportForEach *RSExportForEach::Create(RSContext *Context, const clang::FunctionDecl *FD) { slangAssert(Context && FD); llvm::StringRef Name = FD->getName(); RSExportForEach *FE; slangAssert(!Name.empty() && "Function must have a name"); FE = new RSExportForEach(Context, Name, FD); if (!FE->validateAndConstructParams(Context, FD)) { return NULL; } clang::ASTContext &Ctx = Context->getASTContext(); std::string Id(DUMMY_RS_TYPE_NAME_PREFIX"helper_foreach_param:"); Id.append(FE->getName()).append(DUMMY_RS_TYPE_NAME_POSTFIX); // Extract the usrData parameter (if we have one) if (FE->mUsrData) { const clang::ParmVarDecl *PVD = FE->mUsrData; clang::QualType QT = PVD->getType().getCanonicalType(); slangAssert(QT->isPointerType() && QT->getPointeeType().isConstQualified()); const clang::ASTContext &C = Context->getASTContext(); if (QT->getPointeeType().getCanonicalType().getUnqualifiedType() == C.VoidTy) { // In the case of using const void*, we can't reflect an appopriate // Java type, so we fall back to just reflecting the ain/aout parameters FE->mUsrData = NULL; } else { clang::RecordDecl *RD = clang::RecordDecl::Create(Ctx, clang::TTK_Struct, Ctx.getTranslationUnitDecl(), clang::SourceLocation(), clang::SourceLocation(), &Ctx.Idents.get(Id)); llvm::StringRef ParamName = PVD->getName(); clang::FieldDecl *FD = clang::FieldDecl::Create(Ctx, RD, clang::SourceLocation(), clang::SourceLocation(), PVD->getIdentifier(), QT->getPointeeType(), NULL, /* BitWidth = */ NULL, /* Mutable = */ false, /* HasInit = */ false); RD->addDecl(FD); RD->completeDefinition(); // Create an export type iff we have a valid usrData type clang::QualType T = Ctx.getTagDeclType(RD); slangAssert(!T.isNull()); RSExportType *ET = RSExportType::Create(Context, T.getTypePtr()); if (ET == NULL) { fprintf(stderr, "Failed to export the function %s. There's at least " "one parameter whose type is not supported by the " "reflection\n", FE->getName().c_str()); return NULL; } slangAssert((ET->getClass() == RSExportType::ExportClassRecord) && "Parameter packet must be a record"); FE->mParamPacketType = static_cast<RSExportRecordType *>(ET); } } if (FE->mIn) { const clang::Type *T = FE->mIn->getType().getCanonicalType().getTypePtr(); FE->mInType = RSExportType::Create(Context, T); } if (FE->mOut) { const clang::Type *T = FE->mOut->getType().getCanonicalType().getTypePtr(); FE->mOutType = RSExportType::Create(Context, T); } return FE; }